aiobungie

A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python.

Getting Started

aiobungie provides 3 different client interfaces to get started with, each serve a different purpose.

  • Client: is probably what you want to get started with first. It provides minimal abstraction for the REST api. Is Pythonic.
  • RESTClient: When you're building a light-weight REST backend. You can use this one. It returns JSON objects instead of dataclasses. This is considered lower-level that Client.
  • RESTPool: when you're serving a large amount of users and want to spawn a session for each. each instance of this pool returns a RESTClient.

Check either the examples or each of those objects's documentation for more information about the usage.

 1# MIT License
 2#
 3# Copyright (c) 2020 - Present nxtlo
 4#
 5# Permission is hereby granted, free of charge, to any person obtaining a copy
 6# of this software and associated documentation files (the "Software"), to deal
 7# in the Software without restriction, including without limitation the rights
 8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in all
13# copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21# SOFTWARE.
22
23"""A statically typed, asynchronous API wrapper for building clients for Bungie's API in Python.
24
25### Getting Started
26
27aiobungie provides 3 different client interfaces to get started with, each serve a different purpose.
28
29* `Client`: is probably what you want to get started with first. It provides minimal abstraction for the REST api. Is [Pythonic](https://stackoverflow.com/questions/84102/what-is-idiomatic-code#84270).
30* `RESTClient`: When you're building a light-weight REST backend. You can use this one. It returns `JSON` objects instead of `dataclasses`.
31This is considered lower-level that `Client`.
32* `RESTPool`: when you're serving a large amount of users and want to spawn a session for each. each instance of this pool returns a `RESTClient`.
33
34Check either the examples or each of those objects's documentation for more information about the usage.
35"""
36
37from __future__ import annotations
38
39from aiobungie import builders
40from aiobungie import crates
41from aiobungie import interfaces
42from aiobungie import traits
43from aiobungie import typedefs
44from aiobungie import url
45from aiobungie.client import Client
46from aiobungie.error import *
47from aiobungie.internal import iterators
48from aiobungie.internal.assets import Image
49from aiobungie.internal.enums import *
50from aiobungie.internal.factory import EmptyFactory
51from aiobungie.internal.factory import Factory
52from aiobungie.internal.iterators import *
53from aiobungie.rest import *
54
55# Activity enums
56from .crates.activity import Difficulty
57
58# Components enums
59from .crates.components import ComponentFields
60from .crates.components import ComponentPrivacy
61
62# Entity enums
63from .crates.entity import GatingScope
64from .crates.entity import ObjectiveUIStyle
65from .crates.entity import ValueUIStyle
66
67# Fireteam enums.
68from .crates.fireteams import FireteamActivity
69from .crates.fireteams import FireteamDate
70from .crates.fireteams import FireteamLanguage
71from .crates.fireteams import FireteamPlatform
72
73# Records enums
74from .crates.records import RecordState
75from .metadata import __about__
76from .metadata import __author__
77from .metadata import __docs__
78from .metadata import __email__
79from .metadata import __license__
80from .metadata import __url__
81from .metadata import __version__
82
83__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
70@attrs.define(auto_exc=True)
71class AiobungieError(RuntimeError):
72    """Base class that all other exceptions inherit from."""

Base class that all other exceptions inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
635@typing.final
636class AmmoType(int, Enum):
637    """AN enum for Detyiny 2 ammo types."""
638
639    NONE = 0
640    PRIMARY = 1
641    SPECIAL = 2
642    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
163@attrs.define(auto_exc=True)
164class BadRequest(HTTPError):
165    """An exception raised when requesting a resource with the provided data is wrong."""
166
167    url: typedefs.StrOrURL | None
168    """The URL/endpoint caused this error."""
169
170    body: typing.Any
171    """The response body."""
172
173    headers: multidict.CIMultiDictProxy[str]
174    """The response headers."""
175
176    http_status: http.HTTPStatus = attrs.field(
177        default=http.HTTPStatus.BAD_REQUEST, init=False
178    )

An exception raised when requesting a resource with the provided data is wrong.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str])
2def __init__(self, message, url, body, headers):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = attr_dict['http_status'].default
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
690@typing.final
691class ClanMemberType(int, Enum):
692    """An enum for bungie clan member types."""
693
694    NONE = 0
695    BEGINNER = 1
696    MEMBER = 2
697    ADMIN = 3
698    ACTING_FOUNDER = 4
699    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
466@typing.final
467class Class(int, Enum):
468    """An Enum for Destiny character classes."""
469
470    TITAN = 0
471    HUNTER = 1
472    WARLOCK = 2
473    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  55class Client(traits.ClientApp):
  56    """Standard Bungie API client implementation.
  57
  58    This client deserialize the REST JSON responses using `aiobungie.Factory`
  59    and returns `aiobungie.crates` Python object implementations of the responses.
  60
  61    Example
  62    -------
  63    ```py
  64    import aiobungie
  65
  66    client = aiobungie.Client('...')
  67
  68    async def main():
  69        async with client.rest:
  70            user = await client.fetch_current_user_memberships('...')
  71            print(user)
  72    ```
  73
  74    Parameters
  75    -----------
  76    token: `str`
  77        Your Bungie's API key or Token from the developer's portal.
  78
  79    Other Parameters
  80    ----------------
  81    max_retries : `int`
  82        The max retries number to retry if the request hit a `5xx` status code.
  83    client_secret : `str | None`
  84        An optional application client secret,
  85        This is only needed if you're fetching OAuth2 tokens with this client.
  86    client_id : `int | None`
  87        An optional application client id,
  88        This is only needed if you're fetching OAuth2 tokens with this client.
  89    debug: `"TRACE" | bool | int`
  90        The level of logging to enable.
  91    """
  92
  93    __slots__ = ("_rest", "_factory")
  94
  95    def __init__(
  96        self,
  97        token: str,
  98        /,
  99        *,
 100        client_secret: str | None = None,
 101        client_id: int | None = None,
 102        max_retries: int = 4,
 103        debug: typing.Literal["TRACE"] | bool | int = False,
 104    ) -> None:
 105        self._rest = rest_.RESTClient(
 106            token,
 107            client_secret=client_secret,
 108            client_id=client_id,
 109            max_retries=max_retries,
 110            debug=debug,
 111        )
 112
 113        self._factory = factory_.Factory(self)
 114
 115    @property
 116    def factory(self) -> factory_.Factory:
 117        return self._factory
 118
 119    @property
 120    def rest(self) -> interfaces.RESTInterface:
 121        return self._rest
 122
 123    @property
 124    def request(self) -> Client:
 125        return self
 126
 127    @property
 128    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 129        return self._rest.metadata
 130
 131    def run(self, fn: collections.Awaitable[typing.Any], debug: bool = False) -> None:
 132        loop = helpers.get_or_make_loop()
 133
 134        try:
 135            if not loop.is_running():
 136                loop.set_debug(debug)
 137                loop.run_until_complete(fn)
 138
 139        except Exception as exc:
 140            raise RuntimeError(f"Failed to run {fn!s}") from exc
 141
 142    # * User methods.
 143
 144    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 145        """Fetch and return a user object of the bungie net user associated with account.
 146
 147        .. warning::
 148            This method requires OAuth2 scope and a Bearer access token.
 149
 150        Parameters
 151        ----------
 152        access_token : `str`
 153            A valid Bearer access token for the authorization.
 154
 155        Returns
 156        -------
 157        `aiobungie.crates.user.User`
 158            A user object includes the Destiny memberships and Bungie.net user.
 159        """
 160        resp = await self.rest.fetch_current_user_memberships(access_token)
 161
 162        return self.factory.deserialize_user(resp)
 163
 164    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 165        """Fetch a Bungie user by their BungieNet id.
 166
 167        .. note::
 168            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 169            for other memberships.
 170
 171        Parameters
 172        ----------
 173        id: `int`
 174            The user id.
 175
 176        Returns
 177        -------
 178        `aiobungie.crates.user.BungieUser`
 179            A Bungie user.
 180
 181        Raises
 182        ------
 183        `aiobungie.error.NotFound`
 184            The user was not found.
 185        """
 186        payload = await self.rest.fetch_bungie_user(id)
 187
 188        return self.factory.deserialize_bungie_user(payload)
 189
 190    async def search_users(
 191        self, name: str, /
 192    ) -> iterators.Iterator[user.SearchableDestinyUser]:
 193        """Search for players and return all players that matches the same name.
 194
 195        Parameters
 196        ----------
 197        name : `str`
 198            The user name.
 199
 200        Returns
 201        -------
 202        `aiobungie.Iterator[aiobungie.crates.SearchableDestinyUser]`
 203            A sequence of the found users with this name.
 204        """
 205        payload = await self.rest.search_users(name)
 206
 207        return iterators.Iterator(
 208            [
 209                self.factory.deserialize_searched_user(user)
 210                for user in payload["searchResults"]
 211            ]
 212        )
 213
 214    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 215        """Fetch all available user themes.
 216
 217        Returns
 218        -------
 219        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 220            A sequence of user themes.
 221        """
 222        data = await self.rest.fetch_user_themes()
 223
 224        return self.factory.deserialize_user_themes(data)
 225
 226    async def fetch_hard_types(
 227        self,
 228        credential: int,
 229        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
 230        /,
 231    ) -> user.HardLinkedMembership:
 232        """Gets any hard linked membership given a credential.
 233        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 234        Cross Save aware.
 235
 236        Parameters
 237        ----------
 238        credential: `int`
 239            A valid SteamID64
 240        type: `aiobungie.CredentialType`
 241            The credential type. This must not be changed
 242            Since its only credential that works "currently"
 243
 244        Returns
 245        -------
 246        `aiobungie.crates.user.HardLinkedMembership`
 247            Information about the hard linked data.
 248        """
 249
 250        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 251
 252        return user.HardLinkedMembership(
 253            id=int(payload["membershipId"]),
 254            type=enums.MembershipType(payload["membershipType"]),
 255            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 256        )
 257
 258    async def fetch_membership_from_id(
 259        self,
 260        id: int,
 261        /,
 262        type: enums.MembershipType | int = enums.MembershipType.NONE,
 263    ) -> user.User:
 264        """Fetch Bungie user's memberships from their id.
 265
 266        Notes
 267        -----
 268        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 269        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 270        see `aiobungie.crates.user.DestinyMembership` for more details.
 271        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 272
 273        Parameters
 274        ----------
 275        id : `int`
 276            The user's id.
 277        type : `aiobungie.MembershipType`
 278            The user's membership type.
 279
 280        Returns
 281        -------
 282        `aiobungie.crates.User`
 283            A Bungie user with their membership types.
 284
 285        Raises
 286        ------
 287        aiobungie.NotFound
 288            The requested user was not found.
 289        """
 290        payload = await self.rest.fetch_membership_from_id(id, type)
 291
 292        return self.factory.deserialize_user(payload)
 293
 294    async def fetch_user_credentials(
 295        self, access_token: str, membership_id: int, /
 296    ) -> collections.Sequence[user.UserCredentials]:
 297        """Fetch an array of credential types attached to the requested account.
 298
 299        .. note::
 300            This method require OAuth2 Bearer access token.
 301
 302        Parameters
 303        ----------
 304        access_token : `str`
 305            The bearer access token associated with the bungie account.
 306        membership_id : `int`
 307            The id of the membership to return.
 308
 309        Returns
 310        -------
 311        `collections.Sequence[aiobungie.crates.UserCredentials]`
 312            A sequence of the attached user credentials.
 313
 314        Raises
 315        ------
 316        `aiobungie.Unauthorized`
 317            The access token was wrong or no access token passed.
 318        """
 319        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 320
 321        return self.factory.deserialize_user_credentials(resp)
 322
 323    # * Destiny 2.
 324
 325    async def fetch_profile(
 326        self,
 327        member_id: int,
 328        type: enums.MembershipType | int,
 329        components: collections.Sequence[enums.ComponentType],
 330        auth: str | None = None,
 331    ) -> components.Component:
 332        """
 333        Fetch a bungie profile passing components to the request.
 334
 335        Parameters
 336        ----------
 337        member_id: `int`
 338            The member's id.
 339        type: `aiobungie.MembershipType`
 340            A valid membership type.
 341        components : `collections.Sequence[aiobungie.ComponentType]`
 342            List of profile components to collect and return.
 343
 344        Other Parameters
 345        ----------------
 346        auth : `str | None`
 347            A Bearer access_token to make the request with.
 348            This is optional and limited to components that only requires an Authorization token.
 349
 350        Returns
 351        --------
 352        `aiobungie.crates.Component`
 353            A Destiny 2 player profile with its components.
 354            Only passed components will be available if they exists. Otherwise they will be `None`
 355
 356        Raises
 357        ------
 358        `aiobungie.MembershipTypeError`
 359            The provided membership type was invalid.
 360        """
 361        data = await self.rest.fetch_profile(member_id, type, components, auth)
 362        return self.factory.deserialize_components(data)
 363
 364    async def fetch_linked_profiles(
 365        self,
 366        member_id: int,
 367        member_type: enums.MembershipType | int,
 368        /,
 369        *,
 370        all: bool = False,
 371    ) -> profile.LinkedProfile:
 372        """Returns a summary information about all profiles linked to the requested member.
 373
 374        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 375
 376        .. note::
 377            It will only return linked accounts whose linkages you are allowed to view.
 378
 379        Parameters
 380        ----------
 381        member_id : `int`
 382            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 383        member_type : `aiobungie.MembershipType`
 384            The type for the membership whose linked Destiny account you want to return.
 385
 386        Other Parameters
 387        ----------------
 388        all : `bool`
 389            If provided and set to `True`, All memberships regardless
 390            of whether they're obscured by overrides will be returned,
 391
 392            If provided and set to `False`, Only available memberships will be returned.
 393            The default for this is `False`.
 394
 395        Returns
 396        -------
 397        `aiobungie.crates.profile.LinkedProfile`
 398            A linked profile object.
 399        """
 400        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 401
 402        return self.factory.deserialize_linked_profiles(resp)
 403
 404    async def fetch_membership(
 405        self,
 406        name: str,
 407        code: int,
 408        /,
 409        type: enums.MembershipType | int = enums.MembershipType.ALL,
 410    ) -> collections.Sequence[user.DestinyMembership]:
 411        """Fetch a Destiny 2 player's memberships.
 412
 413        Parameters
 414        -----------
 415        name: `str`
 416            The unique Bungie player name.
 417        code : `int`
 418            The unique Bungie display name code.
 419        type: `aiobungie.internal.enums.MembershipType`
 420            The player's membership type, e,g. XBOX, STEAM, PSN
 421
 422        Returns
 423        --------
 424        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 425            A sequence of the found Destiny 2 player memberships.
 426            An empty sequence will be returned if no one found.
 427
 428        Raises
 429        ------
 430        `aiobungie.MembershipTypeError`
 431            The provided membership type was invalid.
 432        """
 433        resp = await self.rest.fetch_membership(name, code, type)
 434
 435        return self.factory.deserialize_destiny_memberships(resp)
 436
 437    async def fetch_character(
 438        self,
 439        member_id: int,
 440        membership_type: enums.MembershipType | int,
 441        character_id: int,
 442        components: collections.Sequence[enums.ComponentType],
 443        auth: str | None = None,
 444    ) -> components.CharacterComponent:
 445        """Fetch a Destiny 2 character.
 446
 447        Parameters
 448        ----------
 449        member_id: `int`
 450            A valid bungie member id.
 451        character_id: `int`
 452            The Destiny character id to retrieve.
 453        membership_type: `aiobungie.internal.enums.MembershipType`
 454            The member's membership type.
 455        components: `collections.Sequence[aiobungie.ComponentType]`
 456            Multiple arguments of character components to collect and return.
 457
 458        Other Parameters
 459        ----------------
 460        auth : `str | None`
 461            A Bearer access_token to make the request with.
 462            This is optional and limited to components that only requires an Authorization token.
 463
 464        Returns
 465        -------
 466        `aiobungie.crates.CharacterComponent`
 467            A Bungie character component.
 468
 469        `aiobungie.MembershipTypeError`
 470            The provided membership type was invalid.
 471        """
 472        resp = await self.rest.fetch_character(
 473            member_id, membership_type, character_id, components, auth
 474        )
 475
 476        return self.factory.deserialize_character_component(resp)
 477
 478    async def fetch_unique_weapon_history(
 479        self,
 480        membership_id: int,
 481        character_id: int,
 482        membership_type: enums.MembershipType | int,
 483    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 484        """Fetch details about unique weapon usage for a character. Includes all exotics.
 485
 486        Parameters
 487        ----------
 488        membership_id : `int`
 489            The Destiny user membership id.
 490        character_id : `int`
 491            The character id to retrieve.
 492        membership_type : `aiobungie.aiobungie.MembershipType | int`
 493            The Destiny user's membership type.
 494
 495        Returns
 496        -------
 497        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 498            A sequence of the weapon's extended values.
 499        """
 500        resp = await self._rest.fetch_unique_weapon_history(
 501            membership_id, character_id, membership_type
 502        )
 503
 504        return tuple(
 505            self._factory.deserialize_extended_weapon_values(weapon)
 506            for weapon in resp["weapons"]
 507        )
 508
 509    # * Destiny 2 Activities.
 510
 511    async def fetch_activities(
 512        self,
 513        member_id: int,
 514        character_id: int,
 515        mode: enums.GameMode | int,
 516        *,
 517        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
 518        page: int = 0,
 519        limit: int = 250,
 520    ) -> iterators.Iterator[activity.Activity]:
 521        """Fetch a Destiny 2 activity for the specified character id.
 522
 523        Parameters
 524        ----------
 525        member_id: `int`
 526            The user id that starts with `4611`.
 527        character_id: `int`
 528            The id of the character to retrieve the activities for.
 529        mode: `aiobungie.aiobungie.internal.enums.GameMode | int`
 530            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 531
 532        Other Parameters
 533        ----------------
 534        membership_type: `aiobungie.internal.enums.MembershipType`
 535            The Member ship type, if nothing was passed than it will return all.
 536        page: int
 537            The page number. Default is `0`
 538        limit: int
 539            Limit the returned result. Default is `250`.
 540
 541        Returns
 542        -------
 543        `aiobungie.Iterator[aiobungie.crates.Activity]`
 544            An iterator of the player's activities.
 545
 546        Raises
 547        ------
 548        `aiobungie.MembershipTypeError`
 549            The provided membership type was invalid.
 550        """
 551        resp = await self.rest.fetch_activities(
 552            member_id,
 553            character_id,
 554            mode,
 555            membership_type=membership_type,
 556            page=page,
 557            limit=limit,
 558        )
 559
 560        return self.factory.deserialize_activities(resp)
 561
 562    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 563        """Fetch a post activity details.
 564
 565        Parameters
 566        ----------
 567        instance_id: `int`
 568            The activity instance id.
 569
 570        Returns
 571        -------
 572        `aiobungie.crates.PostActivity`
 573           A post activity object.
 574        """
 575        resp = await self.rest.fetch_post_activity(instance_id)
 576
 577        return self.factory.deserialize_post_activity(resp)
 578
 579    async def fetch_aggregated_activity_stats(
 580        self,
 581        character_id: int,
 582        membership_id: int,
 583        membership_type: enums.MembershipType | int,
 584    ) -> iterators.Iterator[activity.AggregatedActivity]:
 585        """Fetch aggregated activity stats for a character.
 586
 587        Parameters
 588        ----------
 589        character_id: `int`
 590            The id of the character to retrieve the activities for.
 591        membership_id: `int`
 592            The id of the user that started with `4611`.
 593        membership_type: `aiobungie.internal.enums.MembershipType`
 594            The Member ship type.
 595
 596        Returns
 597        -------
 598        `aiobungie.Iterator[aiobungie.crates.AggregatedActivity]`
 599            An iterator of the player's activities.
 600
 601        Raises
 602        ------
 603        `aiobungie.MembershipTypeError`
 604            The provided membership type was invalid.
 605        """
 606        resp = await self.rest.fetch_aggregated_activity_stats(
 607            character_id, membership_id, membership_type
 608        )
 609
 610        return self.factory.deserialize_aggregated_activities(resp)
 611
 612    # * Destiny 2 Clans or GroupsV2.
 613
 614    async def fetch_clan_from_id(
 615        self,
 616        id: int,
 617        /,
 618        access_token: str | None = None,
 619    ) -> clans.Clan:
 620        """Fetch a Bungie Clan by its id.
 621
 622        Parameters
 623        -----------
 624        id: `int`
 625            The clan id.
 626
 627        Returns
 628        --------
 629        `aiobungie.crates.Clan`
 630            An Bungie clan.
 631
 632        Raises
 633        ------
 634        `aiobungie.NotFound`
 635            The clan was not found.
 636        """
 637        resp = await self.rest.fetch_clan_from_id(id, access_token)
 638
 639        return self.factory.deserialize_clan(resp)
 640
 641    async def fetch_clan(
 642        self,
 643        name: str,
 644        /,
 645        access_token: str | None = None,
 646        *,
 647        type: enums.GroupType | int = enums.GroupType.CLAN,
 648    ) -> clans.Clan:
 649        """Fetch a Clan by its name.
 650        This method will return the first clan found with given name.
 651
 652        Parameters
 653        ----------
 654        name: `str`
 655            The clan name
 656
 657        Other Parameters
 658        ----------------
 659        access_token : `str | None`
 660            An optional access token to make the request with.
 661
 662            If the token was bound to a member of the clan,
 663            This field `aiobungie.crates.Clan.current_user_membership` will be available
 664            and will return the membership of the user who made this request.
 665        type : `aiobungie.GroupType`
 666            The group type, Default is aiobungie.GroupType.CLAN.
 667
 668        Returns
 669        -------
 670        `aiobungie.crates.Clan`
 671            A Bungie clan.
 672
 673        Raises
 674        ------
 675        `aiobungie.NotFound`
 676            The clan was not found.
 677        """
 678        resp = await self.rest.fetch_clan(name, access_token, type=type)
 679
 680        return self.factory.deserialize_clan(resp)
 681
 682    async def fetch_clan_conversations(
 683        self, clan_id: int, /
 684    ) -> collections.Sequence[clans.ClanConversation]:
 685        """Fetch the conversations/chat channels of the given clan id.
 686
 687        Parameters
 688        ----------
 689        clan_id : `int`
 690            The clan id.
 691
 692        Returns
 693        `collections.Sequence[aiobungie.crates.ClanConversation]`
 694            A sequence of the clan chat channels.
 695        """
 696        resp = await self.rest.fetch_clan_conversations(clan_id)
 697
 698        return self.factory.deserialize_clan_conversations(resp)
 699
 700    async def fetch_clan_admins(
 701        self, clan_id: int, /
 702    ) -> iterators.Iterator[clans.ClanMember]:
 703        """Fetch the clan founder and admins.
 704
 705        Parameters
 706        ----------
 707        clan_id : `int`
 708            The clan id.
 709
 710        Returns
 711        -------
 712        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
 713            An iterator over the found clan admins and founder.
 714
 715        Raises
 716        ------
 717        `aiobungie.NotFound`
 718            The requested clan was not found.
 719        """
 720        resp = await self.rest.fetch_clan_admins(clan_id)
 721
 722        return self.factory.deserialize_clan_members(resp)
 723
 724    async def fetch_groups_for_member(
 725        self,
 726        member_id: int,
 727        member_type: enums.MembershipType | int,
 728        /,
 729        *,
 730        filter: int = 0,
 731        group_type: enums.GroupType = enums.GroupType.CLAN,
 732    ) -> collections.Sequence[clans.GroupMember]:
 733        """Fetch information about the groups that a given member has joined.
 734
 735        Parameters
 736        ----------
 737        member_id : `int`
 738            The member's id
 739        member_type : `aiobungie.MembershipType`
 740            The member's membership type.
 741
 742        Other Parameters
 743        ----------------
 744        filter : `int`
 745            Filter apply to list of joined groups. This Default to `0`
 746        group_type : `aiobungie.GroupType`
 747            The group's type.
 748            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 749
 750        Returns
 751        -------
 752        `collections.Sequence[aiobungie.crates.GroupMember]`
 753            A sequence of joined groups for the fetched member.
 754        """
 755        resp = await self.rest.fetch_groups_for_member(
 756            member_id, member_type, filter=filter, group_type=group_type
 757        )
 758
 759        return tuple(
 760            self.factory.deserialize_group_member(group) for group in resp["results"]
 761        )
 762
 763    async def fetch_potential_groups_for_member(
 764        self,
 765        member_id: int,
 766        member_type: enums.MembershipType | int,
 767        /,
 768        *,
 769        filter: int = 0,
 770        group_type: enums.GroupType | int = enums.GroupType.CLAN,
 771    ) -> collections.Sequence[clans.GroupMember]:
 772        """Fetch the potential groups for a clan member.
 773
 774        Parameters
 775        ----------
 776        member_id : `int`
 777            The member's id
 778        member_type : `aiobungie.aiobungie.MembershipType | int`
 779            The member's membership type.
 780
 781        Other Parameters
 782        ----------------
 783        filter : `int`
 784            Filter apply to list of joined groups. This Default to `0`
 785        group_type : `aiobungie.aiobungie.GroupType | int`
 786            The group's type.
 787            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 788
 789        Returns
 790        -------
 791        `collections.Sequence[aiobungie.crates.GroupMember]`
 792            A sequence of joined potential groups for the fetched member.
 793        """
 794        resp = await self.rest.fetch_potential_groups_for_member(
 795            member_id, member_type, filter=filter, group_type=group_type
 796        )
 797
 798        return tuple(
 799            self.factory.deserialize_group_member(group) for group in resp["results"]
 800        )
 801
 802    async def fetch_clan_members(
 803        self,
 804        clan_id: int,
 805        /,
 806        *,
 807        name: str | None = None,
 808        type: enums.MembershipType | int = enums.MembershipType.NONE,
 809    ) -> iterators.Iterator[clans.ClanMember]:
 810        """Fetch Bungie clan members.
 811
 812        Parameters
 813        ----------
 814        clan_id : `int`
 815            The clans id
 816
 817        Other Parameters
 818        ----------------
 819        name : `str | None`
 820            If provided, Only players matching this name will be returned.
 821        type : `aiobungie.MembershipType`
 822            An optional clan member's membership type.
 823            This parameter is used to filter the returned results
 824            by the provided membership, For an example XBox memberships only,
 825            Otherwise will return all memberships.
 826
 827        Returns
 828        -------
 829        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
 830            An iterator over the bungie clan members.
 831
 832        Raises
 833        ------
 834        `aiobungie.NotFound`
 835            The clan was not found.
 836        """
 837        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 838
 839        return self.factory.deserialize_clan_members(resp)
 840
 841    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 842        """Fetch the clan banners.
 843
 844        Returns
 845        -------
 846        `collections.Sequence[aiobungie.crates.ClanBanner]`
 847            A sequence of the clan banners.
 848        """
 849        resp = await self.rest.fetch_clan_banners()
 850
 851        return self.factory.deserialize_clan_banners(resp)
 852
 853    # This method is required to be here since it deserialize the clan.
 854    async def kick_clan_member(
 855        self,
 856        access_token: str,
 857        /,
 858        group_id: int,
 859        membership_id: int,
 860        membership_type: enums.MembershipType | int,
 861    ) -> clans.Clan:
 862        """Kick a member from the clan.
 863
 864        .. note::
 865            This request requires OAuth2: oauth2: `AdminGroups` scope.
 866
 867        Parameters
 868        ----------
 869        access_token : `str`
 870            The bearer access token associated with the bungie account.
 871        group_id: `int`
 872            The group id.
 873        membership_id : `int`
 874            The member id to kick.
 875        membership_type : `aiobungie.aiobungie.MembershipType | int`
 876            The member's membership type.
 877
 878        Returns
 879        -------
 880        `aiobungie.crates.clan.Clan`
 881            The clan that the member was kicked from.
 882        """
 883        resp = await self.rest.kick_clan_member(
 884            access_token,
 885            group_id=group_id,
 886            membership_id=membership_id,
 887            membership_type=membership_type,
 888        )
 889
 890        return self.factory.deserialize_clan(resp)
 891
 892    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 893        """Fetch a Bungie clan's weekly reward state.
 894
 895        Parameters
 896        ----------
 897        clan_id : `int`
 898            The clan's id.
 899
 900        Returns
 901        -------
 902        `aiobungie.crates.Milestone`
 903            A runtime status of the clan's milestone data.
 904        """
 905
 906        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 907
 908        return self.factory.deserialize_milestone(resp)
 909
 910    # * Destiny 2 Entities aka Definitions.
 911
 912    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 913        """Fetch a static inventory item entity given a its hash.
 914
 915        Parameters
 916        ----------
 917        hash: `int`
 918            Inventory item's hash.
 919
 920        Returns
 921        -------
 922        `aiobungie.crates.InventoryEntity`
 923            A bungie inventory item.
 924        """
 925        resp = await self.rest.fetch_inventory_item(hash)
 926
 927        return self.factory.deserialize_inventory_entity(resp)
 928
 929    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 930        """Fetch a Destiny objective entity given a its hash.
 931
 932        Parameters
 933        ----------
 934        hash: `int`
 935            objective's hash.
 936
 937        Returns
 938        -------
 939        `aiobungie.crates.ObjectiveEntity`
 940            An objective entity item.
 941        """
 942        resp = await self.rest.fetch_objective_entity(hash)
 943
 944        return self.factory.deserialize_objective_entity(resp)
 945
 946    async def search_entities(
 947        self, name: str, entity_type: str, *, page: int = 0
 948    ) -> iterators.Iterator[entity.SearchableEntity]:
 949        """Search for Destiny2 entities given a name and its type.
 950
 951        Parameters
 952        ----------
 953        name : `str`
 954            The name of the entity, i.e., Thunderlord, One thousand voices.
 955        entity_type : `str`
 956            The type of the entity, AKA Definition,
 957            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 958
 959        Other Parameters
 960        ----------------
 961        page : `int`
 962            An optional page to return. Default to 0.
 963
 964        Returns
 965        -------
 966        `aiobungie.Iterator[aiobungie.crates.SearchableEntity]`
 967            An iterator over the found results matching the provided name.
 968        """
 969        resp = await self.rest.search_entities(name, entity_type, page=page)
 970
 971        return self.factory.deserialize_inventory_results(resp)
 972
 973    # Fireteams
 974
 975    async def fetch_fireteams(
 976        self,
 977        activity_type: fireteams.FireteamActivity | int,
 978        *,
 979        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
 980        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
 981        date_range: int = 0,
 982        page: int = 0,
 983        slots_filter: int = 0,
 984    ) -> collections.Sequence[fireteams.Fireteam]:
 985        """Fetch public Bungie fireteams with open slots.
 986
 987        Parameters
 988        ----------
 989        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
 990            The fireteam activity type.
 991
 992        Other Parameters
 993        ----------------
 994        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
 995            If this is provided. Then the results will be filtered with the given platform.
 996            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
 997        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
 998            A locale language to filter the used language in that fireteam.
 999            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1000        date_range : `int`
1001            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1002        page : `int`
1003            The page number. By default its `0` which returns all available activities.
1004        slots_filter : `int`
1005            Filter the returned fireteams based on available slots. Default is `0`
1006
1007        Returns
1008        -------
1009        `collections.Sequence[fireteams.Fireteam]`
1010            A sequence of `aiobungie.crates.Fireteam`.
1011        """
1012
1013        resp = await self.rest.fetch_fireteams(
1014            activity_type,
1015            platform=platform,
1016            language=language,
1017            date_range=date_range,
1018            page=page,
1019            slots_filter=slots_filter,
1020        )
1021
1022        return self.factory.deserialize_fireteams(resp)
1023
1024    async def fetch_available_clan_fireteams(
1025        self,
1026        access_token: str,
1027        group_id: int,
1028        activity_type: fireteams.FireteamActivity | int,
1029        *,
1030        platform: fireteams.FireteamPlatform | int,
1031        language: fireteams.FireteamLanguage | str,
1032        date_range: int = 0,
1033        page: int = 0,
1034        public_only: bool = False,
1035        slots_filter: int = 0,
1036    ) -> collections.Sequence[fireteams.Fireteam]:
1037        """Fetch a clan's fireteams with open slots.
1038
1039        .. note::
1040            This method requires OAuth2: ReadGroups scope.
1041
1042        Parameters
1043        ----------
1044        access_token : `str`
1045            The bearer access token associated with the bungie account.
1046        group_id : `int`
1047            The group/clan id of the fireteam.
1048        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
1049            The fireteam activity type.
1050
1051        Other Parameters
1052        ----------------
1053        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
1054            If this is provided. Then the results will be filtered with the given platform.
1055            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1056        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1057            A locale language to filter the used language in that fireteam.
1058            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1059        date_range : `int`
1060            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1061        page : `int`
1062            The page number. By default its `0` which returns all available activities.
1063        public_only: `bool`
1064            If set to True, Then only public fireteams will be returned.
1065        slots_filter : `int`
1066            Filter the returned fireteams based on available slots. Default is `0`
1067
1068        Returns
1069        -------
1070        `collections.Sequence[aiobungie.crates.Fireteam]`
1071            A sequence of  fireteams found in the clan.
1072            `None` will be returned if nothing was found.
1073        """
1074        resp = await self.rest.fetch_available_clan_fireteams(
1075            access_token,
1076            group_id,
1077            activity_type,
1078            platform=platform,
1079            language=language,
1080            date_range=date_range,
1081            page=page,
1082            public_only=public_only,
1083            slots_filter=slots_filter,
1084        )
1085
1086        return self.factory.deserialize_fireteams(resp)
1087
1088    async def fetch_clan_fireteam(
1089        self, access_token: str, fireteam_id: int, group_id: int
1090    ) -> fireteams.AvailableFireteam:
1091        """Fetch a specific clan fireteam.
1092
1093        .. note::
1094            This method requires OAuth2: ReadGroups scope.
1095
1096        Parameters
1097        ----------
1098        access_token : `str`
1099            The bearer access token associated with the bungie account.
1100        group_id : `int`
1101            The group/clan id to fetch the fireteam from.
1102        fireteam_id : `int`
1103            The fireteam id to fetch.
1104
1105        Returns
1106        -------
1107        `aiobungie.crates.AvailableFireteam`
1108            A sequence of available fireteams objects.
1109        """
1110        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1111
1112        return self.factory.deserialize_available_fireteam(resp)
1113
1114    async def fetch_my_clan_fireteams(
1115        self,
1116        access_token: str,
1117        group_id: int,
1118        *,
1119        include_closed: bool = True,
1120        platform: fireteams.FireteamPlatform | int,
1121        language: fireteams.FireteamLanguage | str,
1122        filtered: bool = True,
1123        page: int = 0,
1124    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1125        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1126
1127        .. note::
1128            This method requires OAuth2: ReadGroups scope.
1129
1130        Parameters
1131        ----------
1132        access_token : str
1133            The bearer access token associated with the bungie account.
1134        group_id : int
1135            The group/clan id to fetch.
1136
1137        Other Parameters
1138        ----------------
1139        include_closed : `bool`
1140            If provided and set to True, It will also return closed fireteams.
1141            If provided and set to False, It will only return public fireteams. Default is True.
1142        platform : aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int
1143            If this is provided. Then the results will be filtered with the given platform.
1144            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1145        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1146            A locale language to filter the used language in that fireteam.
1147            Defaults to aiobungie.crates.FireteamLanguage.ALL
1148        filtered : `bool`
1149            If set to True, it will filter by clan. Otherwise not. Default is True.
1150        page : `int`
1151            The page number. By default its 0 which returns all available activities.
1152
1153        Returns
1154        -------
1155        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1156            A sequence of available fireteams objects if exists. else `None` will be returned.
1157        """
1158        resp = await self.rest.fetch_my_clan_fireteams(
1159            access_token,
1160            group_id,
1161            include_closed=include_closed,
1162            platform=platform,
1163            language=language,
1164            filtered=filtered,
1165            page=page,
1166        )
1167
1168        return self.factory.deserialize_available_fireteams(resp)
1169
1170    # Friends and social.
1171
1172    async def fetch_friends(
1173        self, access_token: str, /
1174    ) -> collections.Sequence[friends.Friend]:
1175        """Fetch bungie friend list.
1176
1177        .. note::
1178            This requests OAuth2: ReadUserData scope.
1179
1180        Parameters
1181        -----------
1182        access_token : `str`
1183            The bearer access token associated with the bungie account.
1184
1185        Returns
1186        -------
1187        `collections.Sequence[aiobungie.crates.Friend]`
1188            A sequence of the friends associated with that access token.
1189        """
1190
1191        resp = await self.rest.fetch_friends(access_token)
1192
1193        return self.factory.deserialize_friends(resp)
1194
1195    async def fetch_friend_requests(
1196        self, access_token: str, /
1197    ) -> friends.FriendRequestView:
1198        """Fetch pending bungie friend requests queue.
1199
1200        .. note::
1201            This requests OAuth2: ReadUserData scope.
1202
1203        Parameters
1204        -----------
1205        access_token : `str`
1206            The bearer access token associated with the bungie account.
1207
1208        Returns
1209        -------
1210        `aiobungie.crates.FriendRequestView`
1211            A friend requests view of that associated access token.
1212        """
1213
1214        resp = await self.rest.fetch_friend_requests(access_token)
1215
1216        return self.factory.deserialize_friend_requests(resp)
1217
1218    # Applications and Developer portal.
1219
1220    async def fetch_application(self, appid: int, /) -> application.Application:
1221        """Fetch a Bungie application.
1222
1223        Parameters
1224        -----------
1225        appid: `int`
1226            The application id.
1227
1228        Returns
1229        --------
1230        `aiobungie.crates.Application`
1231            A Bungie application.
1232        """
1233        resp = await self.rest.fetch_application(appid)
1234
1235        return self.factory.deserialize_app(resp)
1236
1237    # Milestones
1238
1239    async def fetch_public_milestone_content(
1240        self, milestone_hash: int, /
1241    ) -> milestones.MilestoneContent:
1242        """Fetch the milestone content given its hash.
1243
1244        Parameters
1245        ----------
1246        milestone_hash : `int`
1247            The milestone hash.
1248
1249        Returns
1250        -------
1251        `aiobungie.crates.milestones.MilestoneContent`
1252            A milestone content object.
1253        """
1254        ...
1255        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1256        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client implementation.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

Example
import aiobungie

client = aiobungie.Client('...')

async def main():
    async with client.rest:
        user = await client.fetch_current_user_memberships('...')
        print(user)
Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • debug ("TRACE" | bool | int): The level of logging to enable.
Client( token: str, /, *, client_secret: str | None = None, client_id: int | None = None, max_retries: int = 4, debug: Union[Literal['TRACE'], bool, int] = False)
 95    def __init__(
 96        self,
 97        token: str,
 98        /,
 99        *,
100        client_secret: str | None = None,
101        client_id: int | None = None,
102        max_retries: int = 4,
103        debug: typing.Literal["TRACE"] | bool | int = False,
104    ) -> None:
105        self._rest = rest_.RESTClient(
106            token,
107            client_secret=client_secret,
108            client_id=client_id,
109            max_retries=max_retries,
110            debug=debug,
111        )
112
113        self._factory = factory_.Factory(self)
factory: Factory
115    @property
116    def factory(self) -> factory_.Factory:
117        return self._factory

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface
119    @property
120    def rest(self) -> interfaces.RESTInterface:
121        return self._rest

Returns the REST client for the this client.

request: Client
123    @property
124    def request(self) -> Client:
125        return self

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]
127    @property
128    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
129        return self._rest.metadata

A mutable mapping storage for the user's needs.

def run( self, fn: collections.abc.Awaitable[typing.Any], debug: bool = False) -> None:
131    def run(self, fn: collections.Awaitable[typing.Any], debug: bool = False) -> None:
132        loop = helpers.get_or_make_loop()
133
134        try:
135            if not loop.is_running():
136                loop.set_debug(debug)
137                loop.run_until_complete(fn)
138
139        except Exception as exc:
140            raise RuntimeError(f"Failed to run {fn!s}") from exc

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • fn (collections.Awaitable[Any]): The async function to run.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
144    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
145        """Fetch and return a user object of the bungie net user associated with account.
146
147        .. warning::
148            This method requires OAuth2 scope and a Bearer access token.
149
150        Parameters
151        ----------
152        access_token : `str`
153            A valid Bearer access token for the authorization.
154
155        Returns
156        -------
157        `aiobungie.crates.user.User`
158            A user object includes the Destiny memberships and Bungie.net user.
159        """
160        resp = await self.rest.fetch_current_user_memberships(access_token)
161
162        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
164    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
165        """Fetch a Bungie user by their BungieNet id.
166
167        .. note::
168            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
169            for other memberships.
170
171        Parameters
172        ----------
173        id: `int`
174            The user id.
175
176        Returns
177        -------
178        `aiobungie.crates.user.BungieUser`
179            A Bungie user.
180
181        Raises
182        ------
183        `aiobungie.error.NotFound`
184            The user was not found.
185        """
186        payload = await self.rest.fetch_bungie_user(id)
187
188        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> Iterator[aiobungie.crates.user.SearchableDestinyUser]:
190    async def search_users(
191        self, name: str, /
192    ) -> iterators.Iterator[user.SearchableDestinyUser]:
193        """Search for players and return all players that matches the same name.
194
195        Parameters
196        ----------
197        name : `str`
198            The user name.
199
200        Returns
201        -------
202        `aiobungie.Iterator[aiobungie.crates.SearchableDestinyUser]`
203            A sequence of the found users with this name.
204        """
205        payload = await self.rest.search_users(name)
206
207        return iterators.Iterator(
208            [
209                self.factory.deserialize_searched_user(user)
210                for user in payload["searchResults"]
211            ]
212        )

Search for players and return all players that matches the same name.

Parameters
  • name (str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
214    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
215        """Fetch all available user themes.
216
217        Returns
218        -------
219        `collections.Sequence[aiobungie.crates.user.UserThemes]`
220            A sequence of user themes.
221        """
222        data = await self.rest.fetch_user_themes()
223
224        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: CredentialType | int = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
226    async def fetch_hard_types(
227        self,
228        credential: int,
229        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
230        /,
231    ) -> user.HardLinkedMembership:
232        """Gets any hard linked membership given a credential.
233        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
234        Cross Save aware.
235
236        Parameters
237        ----------
238        credential: `int`
239            A valid SteamID64
240        type: `aiobungie.CredentialType`
241            The credential type. This must not be changed
242            Since its only credential that works "currently"
243
244        Returns
245        -------
246        `aiobungie.crates.user.HardLinkedMembership`
247            Information about the hard linked data.
248        """
249
250        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
251
252        return user.HardLinkedMembership(
253            id=int(payload["membershipId"]),
254            type=enums.MembershipType(payload["membershipType"]),
255            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
256        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: MembershipType | int = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
258    async def fetch_membership_from_id(
259        self,
260        id: int,
261        /,
262        type: enums.MembershipType | int = enums.MembershipType.NONE,
263    ) -> user.User:
264        """Fetch Bungie user's memberships from their id.
265
266        Notes
267        -----
268        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
269        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
270        see `aiobungie.crates.user.DestinyMembership` for more details.
271        * If you only want the bungie user. Consider using `Client.fetch_user` method.
272
273        Parameters
274        ----------
275        id : `int`
276            The user's id.
277        type : `aiobungie.MembershipType`
278            The user's membership type.
279
280        Returns
281        -------
282        `aiobungie.crates.User`
283            A Bungie user with their membership types.
284
285        Raises
286        ------
287        aiobungie.NotFound
288            The requested user was not found.
289        """
290        payload = await self.rest.fetch_membership_from_id(id, type)
291
292        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
294    async def fetch_user_credentials(
295        self, access_token: str, membership_id: int, /
296    ) -> collections.Sequence[user.UserCredentials]:
297        """Fetch an array of credential types attached to the requested account.
298
299        .. note::
300            This method require OAuth2 Bearer access token.
301
302        Parameters
303        ----------
304        access_token : `str`
305            The bearer access token associated with the bungie account.
306        membership_id : `int`
307            The id of the membership to return.
308
309        Returns
310        -------
311        `collections.Sequence[aiobungie.crates.UserCredentials]`
312            A sequence of the attached user credentials.
313
314        Raises
315        ------
316        `aiobungie.Unauthorized`
317            The access token was wrong or no access token passed.
318        """
319        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
320
321        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: MembershipType | int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> aiobungie.crates.components.Component:
325    async def fetch_profile(
326        self,
327        member_id: int,
328        type: enums.MembershipType | int,
329        components: collections.Sequence[enums.ComponentType],
330        auth: str | None = None,
331    ) -> components.Component:
332        """
333        Fetch a bungie profile passing components to the request.
334
335        Parameters
336        ----------
337        member_id: `int`
338            The member's id.
339        type: `aiobungie.MembershipType`
340            A valid membership type.
341        components : `collections.Sequence[aiobungie.ComponentType]`
342            List of profile components to collect and return.
343
344        Other Parameters
345        ----------------
346        auth : `str | None`
347            A Bearer access_token to make the request with.
348            This is optional and limited to components that only requires an Authorization token.
349
350        Returns
351        --------
352        `aiobungie.crates.Component`
353            A Destiny 2 player profile with its components.
354            Only passed components will be available if they exists. Otherwise they will be `None`
355
356        Raises
357        ------
358        `aiobungie.MembershipTypeError`
359            The provided membership type was invalid.
360        """
361        data = await self.rest.fetch_profile(member_id, type, components, auth)
362        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (str | None): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: MembershipType | int, /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
364    async def fetch_linked_profiles(
365        self,
366        member_id: int,
367        member_type: enums.MembershipType | int,
368        /,
369        *,
370        all: bool = False,
371    ) -> profile.LinkedProfile:
372        """Returns a summary information about all profiles linked to the requested member.
373
374        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
375
376        .. note::
377            It will only return linked accounts whose linkages you are allowed to view.
378
379        Parameters
380        ----------
381        member_id : `int`
382            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
383        member_type : `aiobungie.MembershipType`
384            The type for the membership whose linked Destiny account you want to return.
385
386        Other Parameters
387        ----------------
388        all : `bool`
389            If provided and set to `True`, All memberships regardless
390            of whether they're obscured by overrides will be returned,
391
392            If provided and set to `False`, Only available memberships will be returned.
393            The default for this is `False`.
394
395        Returns
396        -------
397        `aiobungie.crates.profile.LinkedProfile`
398            A linked profile object.
399        """
400        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
401
402        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_membership( self, name: str, code: int, /, type: MembershipType | int = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
404    async def fetch_membership(
405        self,
406        name: str,
407        code: int,
408        /,
409        type: enums.MembershipType | int = enums.MembershipType.ALL,
410    ) -> collections.Sequence[user.DestinyMembership]:
411        """Fetch a Destiny 2 player's memberships.
412
413        Parameters
414        -----------
415        name: `str`
416            The unique Bungie player name.
417        code : `int`
418            The unique Bungie display name code.
419        type: `aiobungie.internal.enums.MembershipType`
420            The player's membership type, e,g. XBOX, STEAM, PSN
421
422        Returns
423        --------
424        `collections.Sequence[aiobungie.crates.DestinyMembership]`
425            A sequence of the found Destiny 2 player memberships.
426            An empty sequence will be returned if no one found.
427
428        Raises
429        ------
430        `aiobungie.MembershipTypeError`
431            The provided membership type was invalid.
432        """
433        resp = await self.rest.fetch_membership(name, code, type)
434
435        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: MembershipType | int, character_id: int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> aiobungie.crates.components.CharacterComponent:
437    async def fetch_character(
438        self,
439        member_id: int,
440        membership_type: enums.MembershipType | int,
441        character_id: int,
442        components: collections.Sequence[enums.ComponentType],
443        auth: str | None = None,
444    ) -> components.CharacterComponent:
445        """Fetch a Destiny 2 character.
446
447        Parameters
448        ----------
449        member_id: `int`
450            A valid bungie member id.
451        character_id: `int`
452            The Destiny character id to retrieve.
453        membership_type: `aiobungie.internal.enums.MembershipType`
454            The member's membership type.
455        components: `collections.Sequence[aiobungie.ComponentType]`
456            Multiple arguments of character components to collect and return.
457
458        Other Parameters
459        ----------------
460        auth : `str | None`
461            A Bearer access_token to make the request with.
462            This is optional and limited to components that only requires an Authorization token.
463
464        Returns
465        -------
466        `aiobungie.crates.CharacterComponent`
467            A Bungie character component.
468
469        `aiobungie.MembershipTypeError`
470            The provided membership type was invalid.
471        """
472        resp = await self.rest.fetch_character(
473            member_id, membership_type, character_id, components, auth
474        )
475
476        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (MembershipType): The member's membership type.
  • components (collections.Sequence[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (str | None): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: MembershipType | int) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
478    async def fetch_unique_weapon_history(
479        self,
480        membership_id: int,
481        character_id: int,
482        membership_type: enums.MembershipType | int,
483    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
484        """Fetch details about unique weapon usage for a character. Includes all exotics.
485
486        Parameters
487        ----------
488        membership_id : `int`
489            The Destiny user membership id.
490        character_id : `int`
491            The character id to retrieve.
492        membership_type : `aiobungie.aiobungie.MembershipType | int`
493            The Destiny user's membership type.
494
495        Returns
496        -------
497        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
498            A sequence of the weapon's extended values.
499        """
500        resp = await self._rest.fetch_unique_weapon_history(
501            membership_id, character_id, membership_type
502        )
503
504        return tuple(
505            self._factory.deserialize_extended_weapon_values(weapon)
506            for weapon in resp["weapons"]
507        )

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
  • membership_id (int): The Destiny user membership id.
  • character_id (int): The character id to retrieve.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny user's membership type.
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: GameMode | int, *, membership_type: MembershipType | int = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> Iterator[aiobungie.crates.activity.Activity]:
511    async def fetch_activities(
512        self,
513        member_id: int,
514        character_id: int,
515        mode: enums.GameMode | int,
516        *,
517        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
518        page: int = 0,
519        limit: int = 250,
520    ) -> iterators.Iterator[activity.Activity]:
521        """Fetch a Destiny 2 activity for the specified character id.
522
523        Parameters
524        ----------
525        member_id: `int`
526            The user id that starts with `4611`.
527        character_id: `int`
528            The id of the character to retrieve the activities for.
529        mode: `aiobungie.aiobungie.internal.enums.GameMode | int`
530            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
531
532        Other Parameters
533        ----------------
534        membership_type: `aiobungie.internal.enums.MembershipType`
535            The Member ship type, if nothing was passed than it will return all.
536        page: int
537            The page number. Default is `0`
538        limit: int
539            Limit the returned result. Default is `250`.
540
541        Returns
542        -------
543        `aiobungie.Iterator[aiobungie.crates.Activity]`
544            An iterator of the player's activities.
545
546        Raises
547        ------
548        `aiobungie.MembershipTypeError`
549            The provided membership type was invalid.
550        """
551        resp = await self.rest.fetch_activities(
552            member_id,
553            character_id,
554            mode,
555            membership_type=membership_type,
556            page=page,
557            limit=limit,
558        )
559
560        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.aiobungie.internal.enums.GameMode | int): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
562    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
563        """Fetch a post activity details.
564
565        Parameters
566        ----------
567        instance_id: `int`
568            The activity instance id.
569
570        Returns
571        -------
572        `aiobungie.crates.PostActivity`
573           A post activity object.
574        """
575        resp = await self.rest.fetch_post_activity(instance_id)
576
577        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: MembershipType | int) -> Iterator[aiobungie.crates.activity.AggregatedActivity]:
579    async def fetch_aggregated_activity_stats(
580        self,
581        character_id: int,
582        membership_id: int,
583        membership_type: enums.MembershipType | int,
584    ) -> iterators.Iterator[activity.AggregatedActivity]:
585        """Fetch aggregated activity stats for a character.
586
587        Parameters
588        ----------
589        character_id: `int`
590            The id of the character to retrieve the activities for.
591        membership_id: `int`
592            The id of the user that started with `4611`.
593        membership_type: `aiobungie.internal.enums.MembershipType`
594            The Member ship type.
595
596        Returns
597        -------
598        `aiobungie.Iterator[aiobungie.crates.AggregatedActivity]`
599            An iterator of the player's activities.
600
601        Raises
602        ------
603        `aiobungie.MembershipTypeError`
604            The provided membership type was invalid.
605        """
606        resp = await self.rest.fetch_aggregated_activity_stats(
607            character_id, membership_id, membership_type
608        )
609
610        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: str | None = None) -> aiobungie.crates.clans.Clan:
614    async def fetch_clan_from_id(
615        self,
616        id: int,
617        /,
618        access_token: str | None = None,
619    ) -> clans.Clan:
620        """Fetch a Bungie Clan by its id.
621
622        Parameters
623        -----------
624        id: `int`
625            The clan id.
626
627        Returns
628        --------
629        `aiobungie.crates.Clan`
630            An Bungie clan.
631
632        Raises
633        ------
634        `aiobungie.NotFound`
635            The clan was not found.
636        """
637        resp = await self.rest.fetch_clan_from_id(id, access_token)
638
639        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: str | None = None, *, type: GroupType | int = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
641    async def fetch_clan(
642        self,
643        name: str,
644        /,
645        access_token: str | None = None,
646        *,
647        type: enums.GroupType | int = enums.GroupType.CLAN,
648    ) -> clans.Clan:
649        """Fetch a Clan by its name.
650        This method will return the first clan found with given name.
651
652        Parameters
653        ----------
654        name: `str`
655            The clan name
656
657        Other Parameters
658        ----------------
659        access_token : `str | None`
660            An optional access token to make the request with.
661
662            If the token was bound to a member of the clan,
663            This field `aiobungie.crates.Clan.current_user_membership` will be available
664            and will return the membership of the user who made this request.
665        type : `aiobungie.GroupType`
666            The group type, Default is aiobungie.GroupType.CLAN.
667
668        Returns
669        -------
670        `aiobungie.crates.Clan`
671            A Bungie clan.
672
673        Raises
674        ------
675        `aiobungie.NotFound`
676            The clan was not found.
677        """
678        resp = await self.rest.fetch_clan(name, access_token, type=type)
679
680        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
682    async def fetch_clan_conversations(
683        self, clan_id: int, /
684    ) -> collections.Sequence[clans.ClanConversation]:
685        """Fetch the conversations/chat channels of the given clan id.
686
687        Parameters
688        ----------
689        clan_id : `int`
690            The clan id.
691
692        Returns
693        `collections.Sequence[aiobungie.crates.ClanConversation]`
694            A sequence of the clan chat channels.
695        """
696        resp = await self.rest.fetch_clan_conversations(clan_id)
697
698        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> Iterator[aiobungie.crates.clans.ClanMember]:
700    async def fetch_clan_admins(
701        self, clan_id: int, /
702    ) -> iterators.Iterator[clans.ClanMember]:
703        """Fetch the clan founder and admins.
704
705        Parameters
706        ----------
707        clan_id : `int`
708            The clan id.
709
710        Returns
711        -------
712        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
713            An iterator over the found clan admins and founder.
714
715        Raises
716        ------
717        `aiobungie.NotFound`
718            The requested clan was not found.
719        """
720        resp = await self.rest.fetch_clan_admins(clan_id)
721
722        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
724    async def fetch_groups_for_member(
725        self,
726        member_id: int,
727        member_type: enums.MembershipType | int,
728        /,
729        *,
730        filter: int = 0,
731        group_type: enums.GroupType = enums.GroupType.CLAN,
732    ) -> collections.Sequence[clans.GroupMember]:
733        """Fetch information about the groups that a given member has joined.
734
735        Parameters
736        ----------
737        member_id : `int`
738            The member's id
739        member_type : `aiobungie.MembershipType`
740            The member's membership type.
741
742        Other Parameters
743        ----------------
744        filter : `int`
745            Filter apply to list of joined groups. This Default to `0`
746        group_type : `aiobungie.GroupType`
747            The group's type.
748            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
749
750        Returns
751        -------
752        `collections.Sequence[aiobungie.crates.GroupMember]`
753            A sequence of joined groups for the fetched member.
754        """
755        resp = await self.rest.fetch_groups_for_member(
756            member_id, member_type, filter=filter, group_type=group_type
757        )
758
759        return tuple(
760            self.factory.deserialize_group_member(group) for group in resp["results"]
761        )

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
763    async def fetch_potential_groups_for_member(
764        self,
765        member_id: int,
766        member_type: enums.MembershipType | int,
767        /,
768        *,
769        filter: int = 0,
770        group_type: enums.GroupType | int = enums.GroupType.CLAN,
771    ) -> collections.Sequence[clans.GroupMember]:
772        """Fetch the potential groups for a clan member.
773
774        Parameters
775        ----------
776        member_id : `int`
777            The member's id
778        member_type : `aiobungie.aiobungie.MembershipType | int`
779            The member's membership type.
780
781        Other Parameters
782        ----------------
783        filter : `int`
784            Filter apply to list of joined groups. This Default to `0`
785        group_type : `aiobungie.aiobungie.GroupType | int`
786            The group's type.
787            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
788
789        Returns
790        -------
791        `collections.Sequence[aiobungie.crates.GroupMember]`
792            A sequence of joined potential groups for the fetched member.
793        """
794        resp = await self.rest.fetch_potential_groups_for_member(
795            member_id, member_type, filter=filter, group_type=group_type
796        )
797
798        return tuple(
799            self.factory.deserialize_group_member(group) for group in resp["results"]
800        )

Fetch the potential groups for a clan member.

Parameters
  • member_id (int): The member's id
  • member_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • filter (int): Filter apply to list of joined groups. This Default to 0
  • group_type (aiobungie.aiobungie.GroupType | int): The group's type. This is always set to aiobungie.GroupType.CLAN and should not be changed.
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: str | None = None, type: MembershipType | int = <MembershipType.NONE: 0>) -> Iterator[aiobungie.crates.clans.ClanMember]:
802    async def fetch_clan_members(
803        self,
804        clan_id: int,
805        /,
806        *,
807        name: str | None = None,
808        type: enums.MembershipType | int = enums.MembershipType.NONE,
809    ) -> iterators.Iterator[clans.ClanMember]:
810        """Fetch Bungie clan members.
811
812        Parameters
813        ----------
814        clan_id : `int`
815            The clans id
816
817        Other Parameters
818        ----------------
819        name : `str | None`
820            If provided, Only players matching this name will be returned.
821        type : `aiobungie.MembershipType`
822            An optional clan member's membership type.
823            This parameter is used to filter the returned results
824            by the provided membership, For an example XBox memberships only,
825            Otherwise will return all memberships.
826
827        Returns
828        -------
829        `aiobungie.Iterator[aiobungie.crates.ClanMember]`
830            An iterator over the bungie clan members.
831
832        Raises
833        ------
834        `aiobungie.NotFound`
835            The clan was not found.
836        """
837        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
838
839        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (str | None): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
841    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
842        """Fetch the clan banners.
843
844        Returns
845        -------
846        `collections.Sequence[aiobungie.crates.ClanBanner]`
847            A sequence of the clan banners.
848        """
849        resp = await self.rest.fetch_clan_banners()
850
851        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> aiobungie.crates.clans.Clan:
854    async def kick_clan_member(
855        self,
856        access_token: str,
857        /,
858        group_id: int,
859        membership_id: int,
860        membership_type: enums.MembershipType | int,
861    ) -> clans.Clan:
862        """Kick a member from the clan.
863
864        .. note::
865            This request requires OAuth2: oauth2: `AdminGroups` scope.
866
867        Parameters
868        ----------
869        access_token : `str`
870            The bearer access token associated with the bungie account.
871        group_id: `int`
872            The group id.
873        membership_id : `int`
874            The member id to kick.
875        membership_type : `aiobungie.aiobungie.MembershipType | int`
876            The member's membership type.
877
878        Returns
879        -------
880        `aiobungie.crates.clan.Clan`
881            The clan that the member was kicked from.
882        """
883        resp = await self.rest.kick_clan_member(
884            access_token,
885            group_id=group_id,
886            membership_id=membership_id,
887            membership_type=membership_type,
888        )
889
890        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
892    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
893        """Fetch a Bungie clan's weekly reward state.
894
895        Parameters
896        ----------
897        clan_id : `int`
898            The clan's id.
899
900        Returns
901        -------
902        `aiobungie.crates.Milestone`
903            A runtime status of the clan's milestone data.
904        """
905
906        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
907
908        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
912    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
913        """Fetch a static inventory item entity given a its hash.
914
915        Parameters
916        ----------
917        hash: `int`
918            Inventory item's hash.
919
920        Returns
921        -------
922        `aiobungie.crates.InventoryEntity`
923            A bungie inventory item.
924        """
925        resp = await self.rest.fetch_inventory_item(hash)
926
927        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
929    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
930        """Fetch a Destiny objective entity given a its hash.
931
932        Parameters
933        ----------
934        hash: `int`
935            objective's hash.
936
937        Returns
938        -------
939        `aiobungie.crates.ObjectiveEntity`
940            An objective entity item.
941        """
942        resp = await self.rest.fetch_objective_entity(hash)
943
944        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> Iterator[aiobungie.crates.entity.SearchableEntity]:
946    async def search_entities(
947        self, name: str, entity_type: str, *, page: int = 0
948    ) -> iterators.Iterator[entity.SearchableEntity]:
949        """Search for Destiny2 entities given a name and its type.
950
951        Parameters
952        ----------
953        name : `str`
954            The name of the entity, i.e., Thunderlord, One thousand voices.
955        entity_type : `str`
956            The type of the entity, AKA Definition,
957            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
958
959        Other Parameters
960        ----------------
961        page : `int`
962            An optional page to return. Default to 0.
963
964        Returns
965        -------
966        `aiobungie.Iterator[aiobungie.crates.SearchableEntity]`
967            An iterator over the found results matching the provided name.
968        """
969        resp = await self.rest.search_entities(name, entity_type, page=page)
970
971        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int = <FireteamPlatform.ANY: 0>, language: FireteamLanguage | str = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]:
 975    async def fetch_fireteams(
 976        self,
 977        activity_type: fireteams.FireteamActivity | int,
 978        *,
 979        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
 980        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
 981        date_range: int = 0,
 982        page: int = 0,
 983        slots_filter: int = 0,
 984    ) -> collections.Sequence[fireteams.Fireteam]:
 985        """Fetch public Bungie fireteams with open slots.
 986
 987        Parameters
 988        ----------
 989        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
 990            The fireteam activity type.
 991
 992        Other Parameters
 993        ----------------
 994        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
 995            If this is provided. Then the results will be filtered with the given platform.
 996            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
 997        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
 998            A locale language to filter the used language in that fireteam.
 999            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1000        date_range : `int`
1001            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1002        page : `int`
1003            The page number. By default its `0` which returns all available activities.
1004        slots_filter : `int`
1005            Filter the returned fireteams based on available slots. Default is `0`
1006
1007        Returns
1008        -------
1009        `collections.Sequence[fireteams.Fireteam]`
1010            A sequence of `aiobungie.crates.Fireteam`.
1011        """
1012
1013        resp = await self.rest.fetch_fireteams(
1014            activity_type,
1015            platform=platform,
1016            language=language,
1017            date_range=date_range,
1018            page=page,
1019            slots_filter=slots_filter,
1020        )
1021
1022        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_available_clan_fireteams( self, access_token: str, group_id: int, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int, language: FireteamLanguage | str, date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]:
1024    async def fetch_available_clan_fireteams(
1025        self,
1026        access_token: str,
1027        group_id: int,
1028        activity_type: fireteams.FireteamActivity | int,
1029        *,
1030        platform: fireteams.FireteamPlatform | int,
1031        language: fireteams.FireteamLanguage | str,
1032        date_range: int = 0,
1033        page: int = 0,
1034        public_only: bool = False,
1035        slots_filter: int = 0,
1036    ) -> collections.Sequence[fireteams.Fireteam]:
1037        """Fetch a clan's fireteams with open slots.
1038
1039        .. note::
1040            This method requires OAuth2: ReadGroups scope.
1041
1042        Parameters
1043        ----------
1044        access_token : `str`
1045            The bearer access token associated with the bungie account.
1046        group_id : `int`
1047            The group/clan id of the fireteam.
1048        activity_type : `aiobungie.aiobungie.crates.FireteamActivity | int`
1049            The fireteam activity type.
1050
1051        Other Parameters
1052        ----------------
1053        platform : `aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int`
1054            If this is provided. Then the results will be filtered with the given platform.
1055            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1056        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1057            A locale language to filter the used language in that fireteam.
1058            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1059        date_range : `int`
1060            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1061        page : `int`
1062            The page number. By default its `0` which returns all available activities.
1063        public_only: `bool`
1064            If set to True, Then only public fireteams will be returned.
1065        slots_filter : `int`
1066            Filter the returned fireteams based on available slots. Default is `0`
1067
1068        Returns
1069        -------
1070        `collections.Sequence[aiobungie.crates.Fireteam]`
1071            A sequence of  fireteams found in the clan.
1072            `None` will be returned if nothing was found.
1073        """
1074        resp = await self.rest.fetch_available_clan_fireteams(
1075            access_token,
1076            group_id,
1077            activity_type,
1078            platform=platform,
1079            language=language,
1080            date_range=date_range,
1081            page=page,
1082            public_only=public_only,
1083            slots_filter=slots_filter,
1084        )
1085
1086        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • collections.Sequence[aiobungie.crates.Fireteam]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1088    async def fetch_clan_fireteam(
1089        self, access_token: str, fireteam_id: int, group_id: int
1090    ) -> fireteams.AvailableFireteam:
1091        """Fetch a specific clan fireteam.
1092
1093        .. note::
1094            This method requires OAuth2: ReadGroups scope.
1095
1096        Parameters
1097        ----------
1098        access_token : `str`
1099            The bearer access token associated with the bungie account.
1100        group_id : `int`
1101            The group/clan id to fetch the fireteam from.
1102        fireteam_id : `int`
1103            The fireteam id to fetch.
1104
1105        Returns
1106        -------
1107        `aiobungie.crates.AvailableFireteam`
1108            A sequence of available fireteams objects.
1109        """
1110        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1111
1112        return self.factory.deserialize_available_fireteam(resp)

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: FireteamPlatform | int, language: FireteamLanguage | str, filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1114    async def fetch_my_clan_fireteams(
1115        self,
1116        access_token: str,
1117        group_id: int,
1118        *,
1119        include_closed: bool = True,
1120        platform: fireteams.FireteamPlatform | int,
1121        language: fireteams.FireteamLanguage | str,
1122        filtered: bool = True,
1123        page: int = 0,
1124    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1125        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1126
1127        .. note::
1128            This method requires OAuth2: ReadGroups scope.
1129
1130        Parameters
1131        ----------
1132        access_token : str
1133            The bearer access token associated with the bungie account.
1134        group_id : int
1135            The group/clan id to fetch.
1136
1137        Other Parameters
1138        ----------------
1139        include_closed : `bool`
1140            If provided and set to True, It will also return closed fireteams.
1141            If provided and set to False, It will only return public fireteams. Default is True.
1142        platform : aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int
1143            If this is provided. Then the results will be filtered with the given platform.
1144            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1145        language : `aiobungie.crates.fireteams.FireteamLanguage | str`
1146            A locale language to filter the used language in that fireteam.
1147            Defaults to aiobungie.crates.FireteamLanguage.ALL
1148        filtered : `bool`
1149            If set to True, it will filter by clan. Otherwise not. Default is True.
1150        page : `int`
1151            The page number. By default its 0 which returns all available activities.
1152
1153        Returns
1154        -------
1155        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1156            A sequence of available fireteams objects if exists. else `None` will be returned.
1157        """
1158        resp = await self.rest.fetch_my_clan_fireteams(
1159            access_token,
1160            group_id,
1161            include_closed=include_closed,
1162            platform=platform,
1163            language=language,
1164            filtered=filtered,
1165            page=page,
1166        )
1167
1168        return self.factory.deserialize_available_fireteams(resp)

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1172    async def fetch_friends(
1173        self, access_token: str, /
1174    ) -> collections.Sequence[friends.Friend]:
1175        """Fetch bungie friend list.
1176
1177        .. note::
1178            This requests OAuth2: ReadUserData scope.
1179
1180        Parameters
1181        -----------
1182        access_token : `str`
1183            The bearer access token associated with the bungie account.
1184
1185        Returns
1186        -------
1187        `collections.Sequence[aiobungie.crates.Friend]`
1188            A sequence of the friends associated with that access token.
1189        """
1190
1191        resp = await self.rest.fetch_friends(access_token)
1192
1193        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1195    async def fetch_friend_requests(
1196        self, access_token: str, /
1197    ) -> friends.FriendRequestView:
1198        """Fetch pending bungie friend requests queue.
1199
1200        .. note::
1201            This requests OAuth2: ReadUserData scope.
1202
1203        Parameters
1204        -----------
1205        access_token : `str`
1206            The bearer access token associated with the bungie account.
1207
1208        Returns
1209        -------
1210        `aiobungie.crates.FriendRequestView`
1211            A friend requests view of that associated access token.
1212        """
1213
1214        resp = await self.rest.fetch_friend_requests(access_token)
1215
1216        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1220    async def fetch_application(self, appid: int, /) -> application.Application:
1221        """Fetch a Bungie application.
1222
1223        Parameters
1224        -----------
1225        appid: `int`
1226            The application id.
1227
1228        Returns
1229        --------
1230        `aiobungie.crates.Application`
1231            A Bungie application.
1232        """
1233        resp = await self.rest.fetch_application(appid)
1234
1235        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1239    async def fetch_public_milestone_content(
1240        self, milestone_hash: int, /
1241    ) -> milestones.MilestoneContent:
1242        """Fetch the milestone content given its hash.
1243
1244        Parameters
1245        ----------
1246        milestone_hash : `int`
1247            The milestone hash.
1248
1249        Returns
1250        -------
1251        `aiobungie.crates.milestones.MilestoneContent`
1252            A milestone content object.
1253        """
1254        ...
1255        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1256        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
771@typing.final
772class ClosedReasons(Flag):
773    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
774
775    NONE = 0
776    MATCHMAKING = 1 << 0
777    LOADING = 1 << 1
778    SOLO = 1 << 2
779    """The activity is required to be played solo."""
780    INTERNAL_REASONS = 1 << 3
781    """
782    The user can't be joined for one of a variety of internal reasons.
783    Basically, the game can't let you join at this time,
784    but for reasons that aren't under the control of this user
785    """
786    DISALLOWED_BY_GAME_STATE = 1 << 4
787    """The user's current activity/quest/other transitory game state is preventing joining."""
788    OFFLINE = 32768
789    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy.NONE
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: NONE>
DISABLED = <ComponentFields.PRIVACY: NONE>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
347@typing.final
348class ComponentType(Enum):
349    """An Enum for Destiny 2 profile Components."""
350
351    NONE = 0
352
353    PROFILE = 100
354    PROFILE_INVENTORIES = 102
355    PROFILE_CURRENCIES = 103
356    PROFILE_PROGRESSION = 104
357    ALL_PROFILES = (
358        PROFILE,
359        PROFILE_INVENTORIES,
360        PROFILE_CURRENCIES,
361        PROFILE_PROGRESSION,
362    )
363    """All profile components."""
364
365    VENDORS = 400
366    VENDOR_SALES = 402
367    VENDOR_RECEIPTS = 101
368    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
369    """All vendor components."""
370
371    # Items
372    ITEM_INSTANCES = 300
373    ITEM_OBJECTIVES = 301
374    ITEM_PERKS = 302
375    ITEM_RENDER_DATA = 303
376    ITEM_STATS = 304
377    ITEM_SOCKETS = 305
378    ITEM_TALENT_GRINDS = 306
379    ITEM_PLUG_STATES = 308
380    ITEM_PLUG_OBJECTIVES = 309
381    ITEM_REUSABLE_PLUGS = 310
382
383    ALL_ITEMS = (
384        ITEM_PLUG_OBJECTIVES,
385        ITEM_PLUG_STATES,
386        ITEM_SOCKETS,
387        ITEM_INSTANCES,
388        ITEM_OBJECTIVES,
389        ITEM_PERKS,
390        ITEM_RENDER_DATA,
391        ITEM_STATS,
392        ITEM_TALENT_GRINDS,
393        ITEM_REUSABLE_PLUGS,
394    )
395    """All item components."""
396
397    PLATFORM_SILVER = 105
398    KIOSKS = 500
399    CURRENCY_LOOKUPS = 600
400    PRESENTATION_NODES = 700
401    COLLECTIBLES = 800
402    RECORDS = 900
403    TRANSITORY = 1000
404    METRICS = 1100
405    INVENTORIES = 102
406    STRING_VARIABLES = 1200
407    CRAFTABLES = 1300
408
409    CHARACTERS = 200
410    CHARACTER_INVENTORY = 201
411    CHARECTER_PROGRESSION = 202
412    CHARACTER_RENDER_DATA = 203
413    CHARACTER_ACTIVITIES = 204
414    CHARACTER_EQUIPMENT = 205
415    CHARACTER_LOADOUTS = 206
416
417    ALL_CHARACTERS = (
418        CHARACTERS,
419        CHARACTER_INVENTORY,
420        CHARECTER_PROGRESSION,
421        CHARACTER_RENDER_DATA,
422        CHARACTER_ACTIVITIES,
423        CHARACTER_EQUIPMENT,
424        CHARACTER_LOADOUTS,
425        RECORDS,
426    )
427    """All character components."""
428
429    # Ignores: We those are iterables, They're tuples.
430    ALL = (
431        *ALL_PROFILES,  # pyright: ignore[reportGeneralTypeIssues]
432        *ALL_CHARACTERS,  # pyright: ignore[reportGeneralTypeIssues]
433        *ALL_VENDORS,  # pyright: ignore[reportGeneralTypeIssues]
434        *ALL_ITEMS,  # pyright: ignore[reportGeneralTypeIssues]
435        RECORDS,
436        CURRENCY_LOOKUPS,
437        PRESENTATION_NODES,
438        COLLECTIBLES,
439        KIOSKS,
440        METRICS,
441        PLATFORM_SILVER,
442        INVENTORIES,
443        STRING_VARIABLES,
444        TRANSITORY,
445        CRAFTABLES,
446    )
447    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
CHARACTER_LOADOUTS = <ComponentType.CHARACTER_LOADOUTS: 206>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 206, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 206, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
653@typing.final
654class CredentialType(int, Enum):
655    """The types of the accounts system supports at bungie."""
656
657    NONE = 0
658    XUID = 1
659    PSNID = 2
660    WILD = 3
661    FAKE = 4
662    FACEBOOK = 5
663    GOOGLE = 8
664    WINDOWS = 9
665    DEMONID = 10
666    STEAMID = 12
667    BATTLENETID = 14
668    STADIAID = 16
669    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
531@typing.final
532class DamageType(int, Enum):
533    """Enums for Destiny Damage types"""
534
535    NONE = 0
536    KINETIC = 1
537    ARC = 2
538    SOLAR = 3
539    VOID = 4
540    RAID = 5
541    """This is a special damage type reserved for some raid activity encounters."""
542    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
63@typing.final
64class Difficulty(int, enums.Enum):
65    """An enum for activities difficulties."""
66
67    TRIVIAL = 0
68    EASY = 1
69    NORMAL = 2
70    CHALLENGING = 3
71    HARD = 4
72    BRAVE = 5
73    ALMOST_IMPOSSIBLE = 6
74    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
149@typing.final
150class Dungeon(int, Enum):
151    """An Enum for all available Dungeon/Like missions in Destiny 2."""
152
153    NORMAL_PRESAGE = 2124066889
154    """Normal Presage"""
155
156    MASTER_PRESAGE = 4212753278
157    """Master Presage"""
158
159    HARBINGER = 1738383283
160    """Harbinger"""
161
162    PROPHECY = 4148187374
163    """Prophecy"""
164
165    MASTER_POH = 785700673
166    """Master Pit of Heresy?"""
167
168    LEGEND_POH = 785700678
169    """Legend Pit of Heresy?"""
170
171    POH = 1375089621
172    """Normal Pit of Heresy."""
173
174    SHATTERED = 2032534090
175    """Shattered Throne"""
176
177    GOA_LEGEND = 4078656646
178    """Grasp of Avarice legend."""
179
180    GOA_MASTER = 3774021532
181    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class EmptyFactory(aiobungie.Factory):
2420class EmptyFactory(Factory):
2421    """A stand-alone factory that doesn't require a client instance.
2422
2423    # Example
2424    ---------
2425    ```py
2426    # We'll implement a serializable RESTClient.
2427    @dataclass(slots=True)
2428    class MyClient(aiobungie.traits.Serializable):
2429        rest = aiobungie.RESTClient(env["CLIENT_TOKEN"])
2430        my_name = "Fate怒"
2431        my_code = 4275
2432
2433        # Must implement this one method.
2434        @property
2435        def factory(self) -> aiobungie.EmptyFactory:
2436            # Return an empty factory
2437            return aiobungie.EmptyFactory()
2438
2439        async def my_memberships(self) -> Sequence[aiobungie.crates.DestinyMembership]:
2440            # Note, Do not call methods within objects, Since this is an empty
2441            # factory, The client reference that makes these calls will be `None`.
2442            response = await self.rest.fetch_membership(self.my_name, self.my_code)
2443            return self.factory.deserialize_destiny_memberships(response)
2444
2445
2446        async def main() -> None:
2447            client = MyClient()
2448            async with client.client:
2449                print(await client.my_memberships())
2450
2451    asyncio.run(main())
2452    ```
2453    """
2454
2455    __slots__ = ()
2456
2457    if typing.TYPE_CHECKING:
2458        # We explicitly want this to be `None`.
2459        _net: None
2460
2461    def __init__(self, net: None = None) -> None:
2462        self._net = net

A stand-alone factory that doesn't require a client instance.

# Example

# We'll implement a serializable RESTClient.
@dataclass(slots=True)
class MyClient(aiobungie.traits.Serializable):
    rest = aiobungie.RESTClient(env["CLIENT_TOKEN"])
    my_name = "Fate怒"
    my_code = 4275

    # Must implement this one method.
    @property
    def factory(self) -> aiobungie.EmptyFactory:
        # Return an empty factory
        return aiobungie.EmptyFactory()

    async def my_memberships(self) -> Sequence[aiobungie.crates.DestinyMembership]:
        # Note, Do not call methods within objects, Since this is an empty
        # factory, The client reference that makes these calls will be `None`.
        response = await self.rest.fetch_membership(self.my_name, self.my_code)
        return self.factory.deserialize_destiny_memberships(response)


    async def main() -> None:
        client = MyClient()
        async with client.client:
            print(await client.my_memberships())

asyncio.run(main())
EmptyFactory(net: None = None)
2461    def __init__(self, net: None = None) -> None:
2462        self._net = net
Inherited Members
Factory
deserialize_bungie_user
deserialize_partial_bungie_user
deserialize_destiny_membership
deserialize_destiny_memberships
deserialize_user
deserialize_searched_user
deserialize_user_credentials
deserialize_user_themes
deserialize_clan
deserialize_clan_member
deserialize_clan_members
deserialize_group_member
deserialize_clan_conversations
deserialize_app_owner
deserialize_app
deserialize_profile
deserialize_profile_item
deserialize_objectives
deserialize_records
deserialize_character_records
deserialize_character_dye
deserialize_character_customization
deserialize_character_minimal_equipments
deserialize_character_render_data
deserialize_available_activity
deserialize_character_activity
deserialize_profile_items
deserialize_progressions
deserialize_milestone
deserialize_characters
deserialize_character
deserialize_character_equipments
deserialize_character_activities
deserialize_characters_render_data
deserialize_character_progressions
deserialize_character_progressions_mapping
deserialize_characters_records
deserialize_profile_records
deserialize_craftables_component
deserialize_components
deserialize_items_component
deserialize_character_component
deserialize_inventory_results
deserialize_inventory_entity
deserialize_objective_entity
deserialize_activity
deserialize_activities
deserialize_extended_weapon_values
deserialize_post_activity_player
deserialize_post_activity
deserialize_aggregated_activity
deserialize_aggregated_activities
deserialize_linked_profiles
deserialize_clan_banners
deserialize_public_milestone_content
deserialize_friend
deserialize_friends
deserialize_friend_requests
deserialize_fireteams
deserialize_fireteam_destiny_users
deserialize_fireteam_members
deserialize_available_fireteam
deserialize_available_fireteams
deserialize_fireteam_party
deserialize_seasonal_artifact
deserialize_profile_progression
deserialize_instanced_item
deserialize_item_energy
deserialize_item_perk
deserialize_item_socket
deserialize_item_stats_view
deserialize_plug_item_state
class Enum(enum.Enum):
69class Enum(__enum.Enum):
70    """Builtin Python enum with extra handlings."""
71
72    @property
73    def name(self) -> str:
74        return self._name_
75
76    @property
77    def value(self) -> typing.Any:
78        return self._value_
79
80    def __str__(self) -> str:
81        return self._name_
82
83    def __repr__(self) -> str:
84        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
85
86    def __int__(self) -> int:
87        return int(self.value)

Builtin Python enum with extra handlings.

name: str
72    @property
73    def name(self) -> str:
74        return self._name_

The name of the Enum member.

value: Any
76    @property
77    def value(self) -> typing.Any:
78        return self._value_

The value of the Enum member.

class Factory(aiobungie.interfaces.factory.FactoryInterface):
  60class Factory(interfaces.FactoryInterface):
  61    """The base deserialization factory class for all aiobungie objects.
  62
  63    This entity factory is used to deserialize JSON responses from the REST client and turning them
  64    into a `aiobungie.crates` Python classes.
  65    """
  66
  67    __slots__ = ("_net",)
  68
  69    def __init__(self, net: traits.Netrunner) -> None:
  70        self._net = net
  71
  72    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  73        return user.BungieUser(
  74            id=int(data["membershipId"]),
  75            created_at=time.clean_date(data["firstAccess"]),
  76            name=data.get("cachedBungieGlobalDisplayName"),
  77            is_deleted=data["isDeleted"],
  78            about=data["about"],
  79            updated_at=time.clean_date(data["lastUpdate"]),
  80            psn_name=data.get("psnDisplayName", None),
  81            stadia_name=data.get("stadiaDisplayName", None),
  82            steam_name=data.get("steamDisplayName", None),
  83            twitch_name=data.get("twitchDisplayName", None),
  84            blizzard_name=data.get("blizzardDisplayName", None),
  85            status=data["statusText"],
  86            locale=data["locale"],
  87            picture=assets.Image(path=data["profilePicturePath"]),
  88            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  89            unique_name=data.get("uniqueName", None),
  90            theme_id=int(data["profileTheme"]),
  91            show_activity=bool(data["showActivity"]),
  92            theme_name=data["profileThemeName"],
  93            display_title=data["userTitleDisplay"],
  94        )
  95
  96    def deserialize_partial_bungie_user(
  97        self, payload: typedefs.JSONObject
  98    ) -> user.PartialBungieUser:
  99        return user.PartialBungieUser(
 100            net=self._net,
 101            types=tuple(
 102                enums.MembershipType(type_)
 103                for type_ in payload.get("applicableMembershipTypes", ())
 104            ),
 105            name=payload.get("displayName"),
 106            id=int(payload["membershipId"]),
 107            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 108            is_public=payload["isPublic"],
 109            icon=assets.Image(path=payload.get("iconPath", "")),
 110            type=enums.MembershipType(payload["membershipType"]),
 111        )
 112
 113    def deserialize_destiny_membership(
 114        self, payload: typedefs.JSONObject
 115    ) -> user.DestinyMembership:
 116        name: str | None = None
 117        if (raw_name := payload.get("bungieGlobalDisplayName")) is not None:
 118            name = typedefs.unknown(raw_name)
 119
 120        return user.DestinyMembership(
 121            net=self._net,
 122            id=int(payload["membershipId"]),
 123            name=name,
 124            code=payload.get("bungieGlobalDisplayNameCode", None),
 125            last_seen_name=payload.get("LastSeenDisplayName")
 126            or payload.get("displayName")  # noqa: W503
 127            or "",  # noqa: W503
 128            type=enums.MembershipType(payload["membershipType"]),
 129            is_public=payload["isPublic"],
 130            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 131            icon=assets.Image(path=payload.get("iconPath", "")),
 132            types=tuple(
 133                enums.MembershipType(type_)
 134                for type_ in payload.get("applicableMembershipTypes", ())
 135            ),
 136        )
 137
 138    def deserialize_destiny_memberships(
 139        self, data: typedefs.JSONArray
 140    ) -> collections.Sequence[user.DestinyMembership]:
 141        return tuple(
 142            self.deserialize_destiny_membership(membership) for membership in data
 143        )
 144
 145    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 146        primary_membership_id: int | None = None
 147        if raw_primary_id := data.get("primaryMembershipId"):
 148            primary_membership_id = int(raw_primary_id)
 149
 150        return user.User(
 151            bungie_user=self.deserialize_bungie_user(data["bungieNetUser"]),
 152            memberships=self.deserialize_destiny_memberships(
 153                data["destinyMemberships"]
 154            ),
 155            primary_membership_id=primary_membership_id,
 156        )
 157
 158    def deserialize_searched_user(
 159        self, payload: typedefs.JSONObject
 160    ) -> user.SearchableDestinyUser:
 161        code: int | None = None
 162        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 163            code = int(raw_code)
 164
 165        bungie_id: int | None = None
 166        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 167            bungie_id = int(raw_bungie_id)
 168
 169        return user.SearchableDestinyUser(
 170            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
 171            code=code,
 172            bungie_id=bungie_id,
 173            memberships=self.deserialize_destiny_memberships(
 174                payload["destinyMemberships"]
 175            ),
 176        )
 177
 178    def deserialize_user_credentials(
 179        self, payload: typedefs.JSONArray
 180    ) -> collections.Sequence[user.UserCredentials]:
 181        return tuple(
 182            user.UserCredentials(
 183                type=enums.CredentialType(int(creds["credentialType"])),
 184                display_name=creds["credentialDisplayName"],
 185                is_public=creds["isPublic"],
 186                self_as_string=creds.get("credentialAsString"),
 187            )
 188            for creds in payload
 189        )
 190
 191    def deserialize_user_themes(
 192        self, payload: typedefs.JSONArray
 193    ) -> collections.Sequence[user.UserThemes]:
 194        return tuple(
 195            user.UserThemes(
 196                id=int(entry["userThemeId"]),
 197                name=entry["userThemeName"] if "userThemeName" in entry else None,
 198                description=entry["userThemeDescription"]
 199                if "userThemeDescription" in entry
 200                else None,
 201            )
 202            for entry in payload
 203        )
 204
 205    def _deserialize_group_details(
 206        self,
 207        data: typedefs.JSONObject,
 208        current_user_memberships: collections.Mapping[str, clans.ClanMember]
 209        | None = None,
 210        clan_founder: clans.ClanMember | None = None,
 211    ) -> clans.Clan:
 212        features = data["features"]
 213        features_obj = clans.ClanFeatures(
 214            max_members=features["maximumMembers"],
 215            max_membership_types=features["maximumMembershipsOfGroupType"],
 216            capabilities=features["capabilities"],
 217            membership_types=features["membershipTypes"],
 218            invite_permissions=features["invitePermissionOverride"],
 219            update_banner_permissions=features["updateBannerPermissionOverride"],
 220            update_culture_permissions=features["updateCulturePermissionOverride"],
 221            join_level=features["joinLevel"],
 222        )
 223        information: typedefs.JSONObject = data["clanInfo"]
 224        progression: collections.Mapping[int, progressions.Progression] = {
 225            int(prog_hash): self.deserialize_progressions(prog)
 226            for prog_hash, prog in information["d2ClanProgressions"].items()
 227        }
 228
 229        return clans.Clan(
 230            net=self._net,
 231            id=int(data["groupId"]),
 232            name=data["name"],
 233            type=enums.GroupType(data["groupType"]),
 234            created_at=time.clean_date(data["creationDate"]),
 235            member_count=data["memberCount"],
 236            motto=data["motto"],
 237            about=data["about"],
 238            is_public=data["isPublic"],
 239            banner=assets.Image(path=data["bannerPath"]),
 240            avatar=assets.Image(path=data["avatarPath"]),
 241            tags=tuple(data["tags"]),
 242            features=features_obj,
 243            owner=clan_founder,
 244            progressions=progression,
 245            call_sign=information["clanCallsign"],
 246            banner_data=information["clanBannerData"],
 247            chat_security=data["chatSecurity"],
 248            conversation_id=int(data["conversationId"]),
 249            allow_chat=data["allowChat"],
 250            theme=data["theme"],
 251            current_user_membership=current_user_memberships,
 252        )
 253
 254    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 255        current_user_map: collections.Mapping[str, clans.ClanMember] | None = None
 256        if raw_current_user := payload.get("currentUserMemberMap"):
 257            # This will get populated if only it was a GroupsV2.GroupResponse.
 258            # GroupsV2.GetGroupsForMemberResponse doesn't have this field.
 259            current_user_map = {
 260                membership_type: self.deserialize_clan_member(membership)
 261                for membership_type, membership in raw_current_user.items()
 262            }
 263
 264        return self._deserialize_group_details(
 265            data=payload["detail"],
 266            clan_founder=self.deserialize_clan_member(payload["founder"]),
 267            current_user_memberships=current_user_map,
 268        )
 269
 270    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 271        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 272        return clans.ClanMember(
 273            net=self._net,
 274            last_seen_name=destiny_user.last_seen_name,
 275            id=destiny_user.id,
 276            name=destiny_user.name,
 277            icon=destiny_user.icon,
 278            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 279            group_id=int(data["groupId"]),
 280            joined_at=time.clean_date(data["joinDate"]),
 281            types=destiny_user.types,
 282            is_public=destiny_user.is_public,
 283            type=destiny_user.type,
 284            code=destiny_user.code,
 285            is_online=data["isOnline"],
 286            crossave_override=destiny_user.crossave_override,
 287            bungie_user=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 288            if "bungieNetUserInfo" in data
 289            else None,
 290            member_type=enums.ClanMemberType(int(data["memberType"])),
 291        )
 292
 293    def deserialize_clan_members(
 294        self, data: typedefs.JSONObject, /
 295    ) -> iterators.Iterator[clans.ClanMember]:
 296        return iterators.Iterator(
 297            self.deserialize_clan_member(member) for member in data["results"]
 298        )
 299
 300    def deserialize_group_member(
 301        self, payload: typedefs.JSONObject
 302    ) -> clans.GroupMember:
 303        member = payload["member"]
 304        return clans.GroupMember(
 305            net=self._net,
 306            join_date=time.clean_date(member["joinDate"]),
 307            group_id=int(member["groupId"]),
 308            member_type=enums.ClanMemberType(member["memberType"]),
 309            is_online=member["isOnline"],
 310            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 311            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 312            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 313            group=self._deserialize_group_details(payload["group"]),
 314        )
 315
 316    def _deserialize_clan_conversation(
 317        self, payload: typedefs.JSONObject
 318    ) -> clans.ClanConversation:
 319        return clans.ClanConversation(
 320            net=self._net,
 321            id=int(payload["conversationId"]),
 322            group_id=int(payload["groupId"]),
 323            name=typedefs.unknown(payload["chatName"]),
 324            chat_enabled=payload["chatEnabled"],
 325            security=payload["chatSecurity"],
 326        )
 327
 328    def deserialize_clan_conversations(
 329        self, payload: typedefs.JSONArray
 330    ) -> collections.Sequence[clans.ClanConversation]:
 331        return tuple(self._deserialize_clan_conversation(conv) for conv in payload)
 332
 333    def deserialize_app_owner(
 334        self, payload: typedefs.JSONObject
 335    ) -> application.ApplicationOwner:
 336        return application.ApplicationOwner(
 337            net=self._net,
 338            name=payload.get("bungieGlobalDisplayName"),
 339            id=int(payload["membershipId"]),
 340            type=enums.MembershipType(payload["membershipType"]),
 341            icon=assets.Image(path=payload["iconPath"]),
 342            is_public=payload["isPublic"],
 343            code=payload.get("bungieGlobalDisplayNameCode", None),
 344        )
 345
 346    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 347        return application.Application(
 348            id=int(payload["applicationId"]),
 349            name=payload["name"],
 350            link=payload["link"],
 351            status=payload["status"],
 352            redirect_url=payload.get("redirectUrl", None),
 353            created_at=time.clean_date(payload["creationDate"]),
 354            published_at=time.clean_date(payload["firstPublished"]),
 355            owner=self.deserialize_app_owner(payload["team"][0]["user"]),
 356            scope=payload.get("scope"),
 357        )
 358
 359    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 360        return character.Character(
 361            net=self._net,
 362            id=int(payload["characterId"]),
 363            gender=enums.Gender(payload["genderType"]),
 364            race=enums.Race(payload["raceType"]),
 365            class_type=enums.Class(payload["classType"]),
 366            emblem=assets.Image(path=payload["emblemBackgroundPath"])
 367            if "emblemBackgroundPath" in payload
 368            else None,
 369            emblem_icon=assets.Image(path=payload["emblemPath"])
 370            if "emblemPath" in payload
 371            else None,
 372            emblem_hash=int(payload["emblemHash"]) if "emblemHash" in payload else None,
 373            last_played=time.clean_date(payload["dateLastPlayed"]),
 374            total_played_time=int(payload["minutesPlayedTotal"]),
 375            member_id=int(payload["membershipId"]),
 376            member_type=enums.MembershipType(payload["membershipType"]),
 377            level=payload["baseCharacterLevel"],
 378            title_hash=payload.get("titleRecordHash", None),
 379            light=payload["light"],
 380            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 381        )
 382
 383    def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile:
 384        payload = payload["data"]
 385        id = int(payload["userInfo"]["membershipId"])
 386        name = payload["userInfo"]["displayName"]
 387        is_public = payload["userInfo"]["isPublic"]
 388        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 389        last_played = time.clean_date(payload["dateLastPlayed"])
 390        character_ids = tuple(int(cid) for cid in payload["characterIds"])
 391        power_cap = payload["currentSeasonRewardPowerCap"]
 392
 393        return profile.Profile(
 394            id=int(id),
 395            name=name,
 396            is_public=is_public,
 397            type=type,
 398            last_played=last_played,
 399            character_ids=character_ids,
 400            power_cap=power_cap,
 401            net=self._net,
 402        )
 403
 404    def deserialize_profile_item(
 405        self, payload: typedefs.JSONObject
 406    ) -> profile.ProfileItemImpl:
 407        instance_id: int | None = None
 408        if raw_instance_id := payload.get("itemInstanceId"):
 409            instance_id = int(raw_instance_id)
 410
 411        version_number: int | None = None
 412        if raw_version := payload.get("versionNumber"):
 413            version_number = int(raw_version)
 414
 415        transfer_status = enums.TransferStatus(payload["transferStatus"])
 416
 417        return profile.ProfileItemImpl(
 418            net=self._net,
 419            hash=payload["itemHash"],
 420            quantity=payload["quantity"],
 421            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 422            location=enums.ItemLocation(payload["location"]),
 423            bucket=payload["bucketHash"],
 424            transfer_status=transfer_status,
 425            lockable=payload["lockable"],
 426            state=enums.ItemState(payload["state"]),
 427            dismantle_permissions=payload["dismantlePermission"],
 428            is_wrapper=payload["isWrapper"],
 429            instance_id=instance_id,
 430            version_number=version_number,
 431            ornament_id=payload.get("overrideStyleItemHash"),
 432        )
 433
 434    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 435        return records.Objective(
 436            net=self._net,
 437            hash=payload["objectiveHash"],
 438            visible=payload["visible"],
 439            complete=payload["complete"],
 440            completion_value=payload["completionValue"],
 441            progress=payload.get("progress"),
 442            destination_hash=payload.get("destinationHash"),
 443            activity_hash=payload.get("activityHash"),
 444        )
 445
 446    # TODO: Remove **nodes and get it directly from the payload.
 447    def deserialize_records(
 448        self,
 449        payload: typedefs.JSONObject,
 450        scores: records.RecordScores | None = None,
 451        **nodes: int,
 452    ) -> records.Record:
 453        objectives: collections.Sequence[records.Objective] | None = None
 454        interval_objectives: collections.Sequence[records.Objective] | None = None
 455        record_state: records.RecordState | int
 456
 457        record_state = records.RecordState(payload["state"])
 458
 459        if raw_objs := payload.get("objectives"):
 460            objectives = tuple(self.deserialize_objectives(obj) for obj in raw_objs)
 461
 462        if raw_interval_objs := payload.get("intervalObjectives"):
 463            interval_objectives = tuple(
 464                self.deserialize_objectives(obj) for obj in raw_interval_objs
 465            )
 466
 467        return records.Record(
 468            scores=scores,
 469            categories_node_hash=nodes.get("categories_hash"),
 470            seals_node_hash=nodes.get("seals_hash"),
 471            state=record_state,
 472            objectives=objectives,
 473            interval_objectives=interval_objectives,
 474            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 475            completion_times=payload.get("completedCount", None),
 476            reward_visibility=payload.get("rewardVisibility"),
 477        )
 478
 479    def deserialize_character_records(
 480        self,
 481        payload: typedefs.JSONObject,
 482        scores: records.RecordScores | None = None,
 483        record_hashes: collections.Sequence[int] = (),
 484    ) -> records.CharacterRecord:
 485        record = self.deserialize_records(payload, scores)
 486        return records.CharacterRecord(
 487            scores=scores,
 488            categories_node_hash=record.categories_node_hash,
 489            seals_node_hash=record.seals_node_hash,
 490            state=record.state,
 491            objectives=record.objectives,
 492            interval_objectives=record.interval_objectives,
 493            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 494            completion_times=payload.get("completedCount"),
 495            reward_visibility=payload.get("rewardVisibility"),
 496            record_hashes=record_hashes,
 497        )
 498
 499    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 500        return character.Dye(
 501            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 502        )
 503
 504    def deserialize_character_customization(
 505        self, payload: typedefs.JSONObject
 506    ) -> character.CustomizationOptions:
 507        return character.CustomizationOptions(
 508            personality=payload["personality"],
 509            face=payload["face"],
 510            skin_color=payload["skinColor"],
 511            lip_color=payload["lipColor"],
 512            eye_color=payload["eyeColor"],
 513            hair_colors=payload.get("hairColors", ()),
 514            feature_colors=payload.get("featureColors", ()),
 515            decal_color=payload["decalColor"],
 516            wear_helmet=payload["wearHelmet"],
 517            hair_index=payload["hairIndex"],
 518            feature_index=payload["featureIndex"],
 519            decal_index=payload["decalIndex"],
 520        )
 521
 522    def deserialize_character_minimal_equipments(
 523        self, payload: typedefs.JSONObject
 524    ) -> character.MinimalEquipments:
 525        if raw_dyes := payload.get("dyes"):
 526            dyes = tuple(self.deserialize_character_dye(dye) for dye in raw_dyes)
 527        else:
 528            dyes = ()
 529
 530        return character.MinimalEquipments(
 531            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 532        )
 533
 534    def deserialize_character_render_data(
 535        self, payload: typedefs.JSONObject, /
 536    ) -> character.RenderedData:
 537        return character.RenderedData(
 538            net=self._net,
 539            customization=self.deserialize_character_customization(
 540                payload["customization"]
 541            ),
 542            custom_dyes=tuple(
 543                self.deserialize_character_dye(dye)
 544                for dye in payload["customDyes"]
 545                if dye
 546            ),
 547            equipment=tuple(
 548                self.deserialize_character_minimal_equipments(equipment)
 549                for equipment in payload["peerView"]["equipment"]
 550            ),
 551        )
 552
 553    def deserialize_available_activity(
 554        self, payload: typedefs.JSONObject
 555    ) -> activity.AvailableActivity:
 556        return activity.AvailableActivity(
 557            hash=payload["activityHash"],
 558            is_new=payload["isNew"],
 559            is_completed=payload["isCompleted"],
 560            is_visible=payload["isVisible"],
 561            display_level=payload.get("displayLevel"),
 562            recommended_light=payload.get("recommendedLight"),
 563            difficulty=activity.Difficulty(payload["difficultyTier"]),
 564            can_join=payload["canJoin"],
 565            can_lead=payload["canLead"],
 566        )
 567
 568    def deserialize_character_activity(
 569        self, payload: typedefs.JSONObject
 570    ) -> activity.CharacterActivity:
 571        current_mode: enums.GameMode | None = None
 572        if raw_current_mode := payload.get("currentActivityModeType"):
 573            current_mode = enums.GameMode(raw_current_mode)
 574
 575        if raw_current_modes := payload.get("currentActivityModeTypes"):
 576            current_mode_types = tuple(
 577                enums.GameMode(type_) for type_ in raw_current_modes
 578            )
 579        else:
 580            current_mode_types = ()
 581
 582        return activity.CharacterActivity(
 583            date_started=time.clean_date(payload["dateActivityStarted"]),
 584            current_hash=payload["currentActivityHash"],
 585            current_mode_hash=payload["currentActivityModeHash"],
 586            current_mode=current_mode,
 587            current_mode_hashes=payload.get("currentActivityModeHashes", ()),
 588            current_mode_types=current_mode_types,
 589            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 590            last_story_hash=payload["lastCompletedStoryHash"],
 591            available_activities=tuple(
 592                self.deserialize_available_activity(activity_)
 593                for activity_ in payload["availableActivities"]
 594            ),
 595        )
 596
 597    def deserialize_profile_items(
 598        self, payload: typedefs.JSONObject, /
 599    ) -> collections.Sequence[profile.ProfileItemImpl]:
 600        return tuple(self.deserialize_profile_item(item) for item in payload["items"])
 601
 602    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 603        return records.Node(
 604            state=int(payload["state"]),
 605            objective=self.deserialize_objectives(payload["objective"])
 606            if "objective" in payload
 607            else None,
 608            progress_value=int(payload["progressValue"]),
 609            completion_value=int(payload["completionValue"]),
 610            record_category_score=int(payload["recordCategoryScore"])
 611            if "recordCategoryScore" in payload
 612            else None,
 613        )
 614
 615    @staticmethod
 616    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 617        recent_collectibles: collections.Collection[int] | None = None
 618        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 619            recent_collectibles = tuple(
 620                int(item_hash) for item_hash in raw_recent_collectibles
 621            )
 622
 623        collectibles: dict[int, int] = {}
 624        for item_hash, mapping in payload["collectibles"].items():
 625            collectibles[int(item_hash)] = int(mapping["state"])
 626
 627        return items.Collectible(
 628            recent_collectibles=recent_collectibles,
 629            collectibles=collectibles,
 630            collection_category_hash=int(payload["collectionCategoriesRootNodeHash"]),
 631            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 632        )
 633
 634    @staticmethod
 635    def _deserialize_currencies(
 636        payload: typedefs.JSONObject,
 637    ) -> collections.Sequence[items.Currency]:
 638        return tuple(
 639            items.Currency(hash=int(item_hash), amount=int(amount))
 640            for item_hash, amount in payload["itemQuantities"].items()
 641        )
 642
 643    def deserialize_progressions(
 644        self, payload: typedefs.JSONObject
 645    ) -> progressions.Progression:
 646        return progressions.Progression(
 647            hash=int(payload["progressionHash"]),
 648            level=int(payload["level"]),
 649            cap=int(payload["levelCap"]),
 650            daily_limit=int(payload["dailyLimit"]),
 651            weekly_limit=int(payload["weeklyLimit"]),
 652            current_progress=int(payload["currentProgress"]),
 653            daily_progress=int(payload["dailyProgress"]),
 654            needed=int(payload["progressToNextLevel"]),
 655            next_level=int(payload["nextLevelAt"]),
 656        )
 657
 658    def _deserialize_factions(
 659        self, payload: typedefs.JSONObject
 660    ) -> progressions.Factions:
 661        progs = self.deserialize_progressions(payload)
 662        return progressions.Factions(
 663            hash=progs.hash,
 664            level=progs.level,
 665            cap=progs.cap,
 666            daily_limit=progs.daily_limit,
 667            weekly_limit=progs.weekly_limit,
 668            current_progress=progs.current_progress,
 669            daily_progress=progs.daily_progress,
 670            needed=progs.needed,
 671            next_level=progs.next_level,
 672            faction_hash=payload["factionHash"],
 673            faction_vendor_hash=payload["factionVendorIndex"],
 674        )
 675
 676    def _deserialize_milestone_available_quest(
 677        self, payload: typedefs.JSONObject
 678    ) -> milestones.MilestoneQuest:
 679        return milestones.MilestoneQuest(
 680            item_hash=payload["questItemHash"],
 681            status=self._deserialize_milestone_quest_status(payload["status"]),
 682        )
 683
 684    def _deserialize_milestone_activity(
 685        self, payload: typedefs.JSONObject
 686    ) -> milestones.MilestoneActivity:
 687        phases: collections.Sequence[milestones.MilestoneActivityPhase] | None = None
 688        if raw_phases := payload.get("phases"):
 689            phases = tuple(
 690                milestones.MilestoneActivityPhase(
 691                    is_completed=obj["complete"], hash=obj["phaseHash"]
 692                )
 693                for obj in raw_phases
 694            )
 695
 696        return milestones.MilestoneActivity(
 697            hash=payload["activityHash"],
 698            challenges=tuple(
 699                self.deserialize_objectives(obj["objective"])
 700                for obj in payload["challenges"]
 701            ),
 702            modifier_hashes=payload.get("modifierHashes"),
 703            boolean_options=payload.get("booleanActivityOptions"),
 704            phases=phases,
 705        )
 706
 707    def _deserialize_milestone_quest_status(
 708        self, payload: typedefs.JSONObject
 709    ) -> milestones.QuestStatus:
 710        return milestones.QuestStatus(
 711            net=self._net,
 712            quest_hash=payload["questHash"],
 713            step_hash=payload["stepHash"],
 714            step_objectives=tuple(
 715                self.deserialize_objectives(objective)
 716                for objective in payload["stepObjectives"]
 717            ),
 718            is_tracked=payload["tracked"],
 719            is_completed=payload["completed"],
 720            started=payload["started"],
 721            item_instance_id=payload["itemInstanceId"],
 722            vendor_hash=payload.get("vendorHash"),
 723            is_redeemed=payload["redeemed"],
 724        )
 725
 726    def _deserialize_milestone_rewards(
 727        self, payload: typedefs.JSONObject
 728    ) -> milestones.MilestoneReward:
 729        return milestones.MilestoneReward(
 730            category_hash=payload["rewardCategoryHash"],
 731            entries=tuple(
 732                milestones.MilestoneRewardEntry(
 733                    entry_hash=entry["rewardEntryHash"],
 734                    is_earned=entry["earned"],
 735                    is_redeemed=entry["redeemed"],
 736                )
 737                for entry in payload["entries"]
 738            ),
 739        )
 740
 741    def deserialize_milestone(
 742        self, payload: typedefs.JSONObject
 743    ) -> milestones.Milestone:
 744        start_date: datetime.datetime | None = None
 745        if raw_start_date := payload.get("startDate"):
 746            start_date = time.clean_date(raw_start_date)
 747
 748        end_date: datetime.datetime | None = None
 749        if raw_end_date := payload.get("endDate"):
 750            end_date = time.clean_date(raw_end_date)
 751
 752        rewards: collections.Collection[milestones.MilestoneReward] | None = None
 753        if raw_rewards := payload.get("rewards"):
 754            rewards = tuple(
 755                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 756            )
 757
 758        activities: collections.Sequence[milestones.MilestoneActivity] | None = None
 759        if raw_activities := payload.get("activities"):
 760            activities = tuple(
 761                self._deserialize_milestone_activity(active)
 762                for active in raw_activities
 763            )
 764
 765        quests: collections.Sequence[milestones.MilestoneQuest] | None = None
 766        if raw_quests := payload.get("availableQuests"):
 767            quests = tuple(
 768                self._deserialize_milestone_available_quest(quest)
 769                for quest in raw_quests
 770            )
 771
 772        vendors: collections.Sequence[milestones.MilestoneVendor] | None = None
 773        if raw_vendors := payload.get("vendors"):
 774            vendors = tuple(
 775                milestones.MilestoneVendor(
 776                    vendor_hash=vendor["vendorHash"],
 777                    preview_itemhash=vendor.get("previewItemHash"),
 778                )
 779                for vendor in raw_vendors
 780            )
 781
 782        return milestones.Milestone(
 783            hash=payload["milestoneHash"],
 784            start_date=start_date,
 785            end_date=end_date,
 786            order=payload["order"],
 787            rewards=rewards,
 788            available_quests=quests,
 789            activities=activities,
 790            vendors=vendors,
 791        )
 792
 793    def _deserialize_artifact_tiers(
 794        self, payload: typedefs.JSONObject
 795    ) -> season.ArtifactTier:
 796        return season.ArtifactTier(
 797            hash=payload["tierHash"],
 798            is_unlocked=payload["isUnlocked"],
 799            points_to_unlock=payload["pointsToUnlock"],
 800            items=tuple(
 801                season.ArtifactTierItem(
 802                    hash=item["itemHash"], is_active=item["isActive"]
 803                )
 804                for item in payload["items"]
 805            ),
 806        )
 807
 808    def deserialize_characters(
 809        self, payload: typedefs.JSONObject
 810    ) -> collections.Mapping[int, character.Character]:
 811        return {
 812            int(char_id): self._set_character_attrs(char)
 813            for char_id, char in payload["data"].items()
 814        }
 815
 816    def deserialize_character(
 817        self, payload: typedefs.JSONObject
 818    ) -> character.Character:
 819        return self._set_character_attrs(payload)
 820
 821    def deserialize_character_equipments(
 822        self, payload: typedefs.JSONObject
 823    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 824        return {
 825            int(char_id): self.deserialize_profile_items(item)
 826            for char_id, item in payload["data"].items()
 827        }
 828
 829    def deserialize_character_activities(
 830        self, payload: typedefs.JSONObject
 831    ) -> collections.Mapping[int, activity.CharacterActivity]:
 832        return {
 833            int(char_id): self.deserialize_character_activity(data)
 834            for char_id, data in payload["data"].items()
 835        }
 836
 837    def deserialize_characters_render_data(
 838        self, payload: typedefs.JSONObject
 839    ) -> collections.Mapping[int, character.RenderedData]:
 840        return {
 841            int(char_id): self.deserialize_character_render_data(data)
 842            for char_id, data in payload["data"].items()
 843        }
 844
 845    def deserialize_character_progressions(
 846        self, payload: typedefs.JSONObject
 847    ) -> character.CharacterProgression:
 848        progressions_ = {
 849            int(prog_id): self.deserialize_progressions(prog)
 850            for prog_id, prog in payload["progressions"].items()
 851        }
 852
 853        factions = {
 854            int(faction_id): self._deserialize_factions(faction)
 855            for faction_id, faction in payload["factions"].items()
 856        }
 857
 858        milestones_ = {
 859            int(milestone_hash): self.deserialize_milestone(milestone)
 860            for milestone_hash, milestone in payload["milestones"].items()
 861        }
 862
 863        uninstanced_item_objectives = {
 864            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 865            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 866        }
 867
 868        artifact = payload["seasonalArtifact"]
 869        seasonal_artifact = season.CharacterScopedArtifact(
 870            hash=artifact["artifactHash"],
 871            points_used=artifact["pointsUsed"],
 872            reset_count=artifact["resetCount"],
 873            tiers=tuple(
 874                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 875            ),
 876        )
 877        checklists = payload["checklists"]
 878
 879        return character.CharacterProgression(
 880            progressions=progressions_,
 881            factions=factions,
 882            checklists=checklists,
 883            milestones=milestones_,
 884            seasonal_artifact=seasonal_artifact,
 885            uninstanced_item_objectives=uninstanced_item_objectives,
 886        )
 887
 888    # fmt: off
 889    def deserialize_character_progressions_mapping(self, payload: typedefs.JSONObject) -> collections.Mapping[int, character.CharacterProgression]:
 890        character_progressions: collections.MutableMapping[int, character.CharacterProgression] = {}
 891        for char_id, data in payload["data"].items():
 892            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)
 893        return character_progressions
 894    # fmt: on
 895
 896    def deserialize_characters_records(
 897        self,
 898        payload: typedefs.JSONObject,
 899    ) -> collections.Mapping[int, records.CharacterRecord]:
 900        return {
 901            int(rec_id): self.deserialize_character_records(
 902                rec, record_hashes=payload.get("featuredRecordHashes", ())
 903            )
 904            for rec_id, rec in payload["records"].items()
 905        }
 906
 907    def deserialize_profile_records(
 908        self, payload: typedefs.JSONObject
 909    ) -> collections.Mapping[int, records.Record]:
 910        raw_profile_records = payload["data"]
 911        scores = records.RecordScores(
 912            current_score=raw_profile_records["score"],
 913            legacy_score=raw_profile_records["legacyScore"],
 914            lifetime_score=raw_profile_records["lifetimeScore"],
 915        )
 916        return {
 917            int(record_id): self.deserialize_records(
 918                record,
 919                scores,
 920                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 921                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 922            )
 923            for record_id, record in raw_profile_records["records"].items()
 924        }
 925
 926    def _deserialize_craftable_socket_plug(
 927        self, payload: typedefs.JSONObject
 928    ) -> items.CraftableSocketPlug:
 929        return items.CraftableSocketPlug(
 930            item_hash=int(payload["plugItemHash"]),
 931            failed_requirement_indexes=payload.get("failedRequirementIndexes", ()),
 932        )
 933
 934    def _deserialize_craftable_socket(
 935        self, payload: typedefs.JSONObject
 936    ) -> items.CraftableSocket:
 937        if raw_plug := payload.get("plug"):
 938            plugs = tuple(
 939                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 940            )
 941        else:
 942            plugs = ()
 943
 944        return items.CraftableSocket(
 945            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 946        )
 947
 948    def _deserialize_craftable_item(
 949        self, payload: typedefs.JSONObject
 950    ) -> items.CraftableItem:
 951        return items.CraftableItem(
 952            is_visible=payload["visible"],
 953            failed_requirement_indexes=payload.get("failedRequirementIndexes", ()),
 954            sockets=tuple(
 955                self._deserialize_craftable_socket(socket)
 956                for socket in payload["sockets"]
 957            ),
 958        )
 959
 960    def deserialize_craftables_component(
 961        self, payload: typedefs.JSONObject
 962    ) -> components.CraftablesComponent:
 963        return components.CraftablesComponent(
 964            net=self._net,
 965            craftables={
 966                int(item_id): self._deserialize_craftable_item(item)
 967                for item_id, item in payload["craftables"].items()
 968                if item is not None
 969            },
 970            crafting_root_node_hash=payload["craftingRootNodeHash"],
 971        )
 972
 973    def deserialize_components(  # noqa: C901 Too complex.
 974        self, payload: typedefs.JSONObject
 975    ) -> components.Component:
 976        # Due to how complex this method is, We'll stick to
 977        # typing.Optional here.
 978
 979        profile_: profile.Profile | None = None
 980        if raw_profile := payload.get("profile"):
 981            profile_ = self.deserialize_profile(raw_profile)
 982
 983        profile_progression: profile.ProfileProgression | None = None
 984        if raw_profile_progression := payload.get("profileProgression"):
 985            profile_progression = self.deserialize_profile_progression(
 986                raw_profile_progression
 987            )
 988
 989        profile_currencies: typing.Optional[
 990            collections.Sequence[profile.ProfileItemImpl]
 991        ] = None
 992        if raw_profile_currencies := payload.get("profileCurrencies"):
 993            if "data" in raw_profile_currencies:
 994                profile_currencies = self.deserialize_profile_items(
 995                    raw_profile_currencies["data"]
 996                )
 997
 998        profile_inventories: typing.Optional[
 999            collections.Sequence[profile.ProfileItemImpl]
1000        ] = None
1001        if raw_profile_inventories := payload.get("profileInventory"):
1002            if "data" in raw_profile_inventories:
1003                profile_inventories = self.deserialize_profile_items(
1004                    raw_profile_inventories["data"]
1005                )
1006
1007        profile_records: typing.Optional[
1008            collections.Mapping[int, records.Record]
1009        ] = None
1010
1011        if raw_profile_records_ := payload.get("profileRecords"):
1012            profile_records = self.deserialize_profile_records(raw_profile_records_)
1013
1014        characters: typing.Optional[
1015            collections.Mapping[int, character.Character]
1016        ] = None
1017        if raw_characters := payload.get("characters"):
1018            characters = self.deserialize_characters(raw_characters)
1019
1020        character_records: typing.Optional[
1021            collections.Mapping[int, records.CharacterRecord]
1022        ] = None
1023
1024        if raw_character_records := payload.get("characterRecords"):
1025            # Had to do it in two steps..
1026            to_update = {}
1027            for _, data in raw_character_records["data"].items():
1028                for record_id, record in data.items():
1029                    to_update[record_id] = record
1030
1031            character_records = {
1032                int(rec_id): self.deserialize_character_records(
1033                    rec, record_hashes=to_update.get("featuredRecordHashes", ())
1034                )
1035                for rec_id, rec in to_update["records"].items()
1036            }
1037
1038        character_equipments: typing.Optional[
1039            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1040        ] = None
1041        if raw_character_equips := payload.get("characterEquipment"):
1042            character_equipments = self.deserialize_character_equipments(
1043                raw_character_equips
1044            )
1045
1046        character_inventories: typing.Optional[
1047            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1048        ] = None
1049        if raw_character_inventories := payload.get("characterInventories"):
1050            if "data" in raw_character_inventories:
1051                character_inventories = self.deserialize_character_equipments(
1052                    raw_character_inventories
1053                )
1054
1055        character_activities: typing.Optional[
1056            collections.Mapping[int, activity.CharacterActivity]
1057        ] = None
1058        if raw_char_acts := payload.get("characterActivities"):
1059            character_activities = self.deserialize_character_activities(raw_char_acts)
1060
1061        character_render_data: typing.Optional[
1062            collections.Mapping[int, character.RenderedData]
1063        ] = None
1064        if raw_character_render_data := payload.get("characterRenderData"):
1065            character_render_data = self.deserialize_characters_render_data(
1066                raw_character_render_data
1067            )
1068
1069        character_progressions: typing.Optional[
1070            collections.Mapping[int, character.CharacterProgression]
1071        ] = None
1072
1073        if raw_character_progressions := payload.get("characterProgressions"):
1074            character_progressions = self.deserialize_character_progressions_mapping(
1075                raw_character_progressions
1076            )
1077
1078        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1079        if raw_profile_string_vars := payload.get("profileStringVariables"):
1080            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1081
1082        character_string_vars: typing.Optional[
1083            collections.Mapping[int, collections.Mapping[int, int]]
1084        ] = None
1085        if raw_character_string_vars := payload.get("characterStringVariables"):
1086            character_string_vars = {
1087                int(char_id): data["integerValuesByHash"]
1088                for char_id, data in raw_character_string_vars["data"].items()
1089            }
1090
1091        metrics: typing.Optional[
1092            collections.Sequence[
1093                collections.Mapping[int, tuple[bool, records.Objective | None]]
1094            ]
1095        ] = None
1096        root_node_hash: int | None = None
1097
1098        if raw_metrics := payload.get("metrics"):
1099            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1100            metrics = tuple(
1101                {
1102                    int(metrics_hash): (
1103                        data["invisible"],
1104                        self.deserialize_objectives(data["objectiveProgress"])
1105                        if "objectiveProgress" in data
1106                        else None,
1107                    )
1108                }
1109                for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1110            )
1111        transitory: fireteams.FireteamParty | None = None
1112        if raw_transitory := payload.get("profileTransitoryData"):
1113            if "data" in raw_transitory:
1114                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1115
1116        item_components: components.ItemsComponent | None = None
1117        if raw_item_components := payload.get("itemComponents"):
1118            item_components = self.deserialize_items_component(raw_item_components)
1119
1120        profile_plugsets: typing.Optional[
1121            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1122        ] = None
1123
1124        if raw_profile_plugs := payload.get("profilePlugSets"):
1125            profile_plugsets = {
1126                int(index): [self.deserialize_plug_item_state(state) for state in data]
1127                for index, data in raw_profile_plugs["data"]["plugs"].items()
1128            }
1129
1130        character_plugsets: typing.Optional[
1131            collections.Mapping[
1132                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1133            ]
1134        ] = None
1135        if raw_char_plugsets := payload.get("characterPlugSets"):
1136            character_plugsets = {
1137                int(char_id): {
1138                    int(index): [
1139                        self.deserialize_plug_item_state(state) for state in data
1140                    ]
1141                    for index, data in inner["plugs"].items()
1142                }
1143                for char_id, inner in raw_char_plugsets["data"].items()
1144            }
1145
1146        character_collectibles: typing.Optional[
1147            collections.Mapping[int, items.Collectible]
1148        ] = None
1149        if raw_character_collectibles := payload.get("characterCollectibles"):
1150            character_collectibles = {
1151                int(char_id): self._deserialize_collectible(data)
1152                for char_id, data in raw_character_collectibles["data"].items()
1153            }
1154
1155        profile_collectibles: items.Collectible | None = None
1156        if raw_profile_collectibles := payload.get("profileCollectibles"):
1157            profile_collectibles = self._deserialize_collectible(
1158                raw_profile_collectibles["data"]
1159            )
1160
1161        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1162        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1163            profile_nodes = {
1164                int(node_hash): self._deserialize_node(node)
1165                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1166            }
1167
1168        character_nodes: typing.Optional[
1169            collections.Mapping[int, collections.Mapping[int, records.Node]]
1170        ] = None
1171        if raw_character_nodes := payload.get("characterPresentationNodes"):
1172            character_nodes = {
1173                int(char_id): {
1174                    int(node_hash): self._deserialize_node(node)
1175                    for node_hash, node in each_character["nodes"].items()
1176                }
1177                for char_id, each_character in raw_character_nodes["data"].items()
1178            }
1179
1180        platform_silver: typing.Optional[
1181            collections.Mapping[str, profile.ProfileItemImpl]
1182        ] = None
1183        if raw_platform_silver := payload.get("platformSilver"):
1184            if "data" in raw_platform_silver:
1185                platform_silver = {
1186                    platform_name: self.deserialize_profile_item(item)
1187                    for platform_name, item in raw_platform_silver["data"][
1188                        "platformSilver"
1189                    ].items()
1190                }
1191
1192        character_currency_lookups: typing.Optional[
1193            collections.Mapping[int, collections.Sequence[items.Currency]]
1194        ] = None
1195        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1196            if "data" in raw_char_lookups:
1197                character_currency_lookups = {
1198                    int(char_id): self._deserialize_currencies(currency)
1199                    for char_id, currency in raw_char_lookups["data"].items()
1200                }
1201
1202        character_craftables: typing.Optional[
1203            collections.Mapping[int, components.CraftablesComponent]
1204        ] = None
1205        if raw_character_craftables := payload.get("characterCraftables"):
1206            if "data" in raw_character_craftables:
1207                character_craftables = {
1208                    int(char_id): self.deserialize_craftables_component(craftable)
1209                    for char_id, craftable in raw_character_craftables["data"].items()
1210                }
1211
1212        return components.Component(
1213            profiles=profile_,
1214            profile_progression=profile_progression,
1215            profile_currencies=profile_currencies,
1216            profile_inventories=profile_inventories,
1217            profile_records=profile_records,
1218            characters=characters,
1219            character_records=character_records,
1220            character_equipments=character_equipments,
1221            character_inventories=character_inventories,
1222            character_activities=character_activities,
1223            character_render_data=character_render_data,
1224            character_progressions=character_progressions,
1225            profile_string_variables=profile_string_vars,
1226            character_string_variables=character_string_vars,
1227            metrics=metrics,
1228            root_node_hash=root_node_hash,
1229            transitory=transitory,
1230            item_components=item_components,
1231            profile_plugsets=profile_plugsets,
1232            character_plugsets=character_plugsets,
1233            character_collectibles=character_collectibles,
1234            profile_collectibles=profile_collectibles,
1235            profile_nodes=profile_nodes,
1236            character_nodes=character_nodes,
1237            platform_silver=platform_silver,
1238            character_currency_lookups=character_currency_lookups,
1239            character_craftables=character_craftables,
1240        )
1241
1242    def deserialize_items_component(
1243        self, payload: typedefs.JSONObject
1244    ) -> components.ItemsComponent:
1245        # Due to how complex this method is, We'll stick to typing.Optional.
1246        instances: typing.Optional[
1247            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1248        ] = None
1249        if raw_instances := payload.get("instances"):
1250            instances = tuple(
1251                {int(ins_id): self.deserialize_instanced_item(item)}
1252                for ins_id, item in raw_instances["data"].items()
1253            )
1254
1255        render_data: typing.Optional[
1256            collections.Mapping[int, tuple[bool, dict[int, int]]]
1257        ] = None
1258        if raw_render_data := payload.get("renderData"):
1259            render_data = {
1260                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1261                for ins_id, data in raw_render_data["data"].items()
1262            }
1263
1264        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1265        if raw_stats := payload.get("stats"):
1266            stats = {}
1267            for ins_id, stat in raw_stats["data"].items():
1268                for _, items_ in stat.items():
1269                    stats[int(ins_id)] = self.deserialize_item_stats_view(items_)
1270
1271        sockets: typing.Optional[
1272            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1273        ] = None
1274        if raw_sockets := payload.get("sockets"):
1275            sockets = {
1276                int(ins_id): tuple(
1277                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1278                )
1279                for ins_id, item in raw_sockets["data"].items()
1280            }
1281
1282        objectives: typing.Optional[
1283            collections.Mapping[int, collections.Sequence[records.Objective]]
1284        ] = None
1285        if raw_objectives := payload.get("objectives"):
1286            objectives = {
1287                int(ins_id): tuple(
1288                    self.deserialize_objectives(objective)
1289                    for objective in data["objectives"]
1290                )
1291                for ins_id, data in raw_objectives["data"].items()
1292            }
1293
1294        perks: typing.Optional[
1295            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1296        ] = None
1297        if raw_perks := payload.get("perks"):
1298            perks = {
1299                int(ins_id): tuple(
1300                    self.deserialize_item_perk(perk) for perk in item["perks"]
1301                )
1302                for ins_id, item in raw_perks["data"].items()
1303            }
1304
1305        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1306        if raw_plug_states := payload.get("plugStates"):
1307            plug_states = tuple(
1308                self.deserialize_plug_item_state(plug)
1309                for _, plug in raw_plug_states["data"].items()
1310            )
1311
1312        reusable_plugs: typing.Optional[
1313            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1314        ] = None
1315        if raw_re_plugs := payload.get("reusablePlugs"):
1316            reusable_plugs = {
1317                int(ins_id): tuple(
1318                    self.deserialize_plug_item_state(state) for state in inner
1319                )
1320                for ins_id, plug in raw_re_plugs["data"].items()
1321                for inner in tuple(plug["plugs"].values())
1322            }
1323
1324        plug_objectives: typing.Optional[
1325            collections.Mapping[
1326                int, collections.Mapping[int, collections.Collection[records.Objective]]
1327            ]
1328        ] = None
1329        if raw_plug_objectives := payload.get("plugObjectives"):
1330            plug_objectives = {
1331                int(ins_id): {
1332                    int(obj_hash): tuple(
1333                        self.deserialize_objectives(obj) for obj in objs
1334                    )
1335                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1336                }
1337                for ins_id, inner in raw_plug_objectives["data"].items()
1338            }
1339
1340        return components.ItemsComponent(
1341            sockets=sockets,
1342            stats=stats,
1343            render_data=render_data,
1344            instances=instances,
1345            objectives=objectives,
1346            perks=perks,
1347            plug_states=plug_states,
1348            reusable_plugs=reusable_plugs,
1349            plug_objectives=plug_objectives,
1350        )
1351
1352    def deserialize_character_component(
1353        self, payload: typedefs.JSONObject
1354    ) -> components.CharacterComponent:
1355        character_: character.Character | None = None
1356        if raw_singular_character := payload.get("character"):
1357            character_ = self.deserialize_character(raw_singular_character["data"])
1358
1359        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1360        if raw_inventory := payload.get("inventory"):
1361            if "data" in raw_inventory:
1362                inventory = self.deserialize_profile_items(raw_inventory["data"])
1363
1364        activities: activity.CharacterActivity | None = None
1365        if raw_activities := payload.get("activities"):
1366            activities = self.deserialize_character_activity(raw_activities["data"])
1367
1368        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1369        if raw_equipments := payload.get("equipment"):
1370            equipment = self.deserialize_profile_items(raw_equipments["data"])
1371
1372        progressions_: character.CharacterProgression | None = None
1373        if raw_progressions := payload.get("progressions"):
1374            progressions_ = self.deserialize_character_progressions(
1375                raw_progressions["data"]
1376            )
1377
1378        render_data: character.RenderedData | None = None
1379        if raw_render_data := payload.get("renderData"):
1380            render_data = self.deserialize_character_render_data(
1381                raw_render_data["data"]
1382            )
1383
1384        character_records: typing.Optional[
1385            collections.Mapping[int, records.CharacterRecord]
1386        ] = None
1387        if raw_char_records := payload.get("records"):
1388            character_records = self.deserialize_characters_records(
1389                raw_char_records["data"]
1390            )
1391
1392        item_components: components.ItemsComponent | None = None
1393        if raw_item_components := payload.get("itemComponents"):
1394            item_components = self.deserialize_items_component(raw_item_components)
1395
1396        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1397        if raw_nodes := payload.get("presentationNodes"):
1398            nodes = {
1399                int(node_hash): self._deserialize_node(node)
1400                for node_hash, node in raw_nodes["data"]["nodes"].items()
1401            }
1402
1403        collectibles: items.Collectible | None = None
1404        if raw_collectibles := payload.get("collectibles"):
1405            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1406
1407        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1408        if raw_currencies := payload.get("currencyLookups"):
1409            if "data" in raw_currencies:
1410                currency_lookups = self._deserialize_currencies(raw_currencies)
1411
1412        return components.CharacterComponent(
1413            activities=activities,
1414            equipment=equipment,
1415            inventory=inventory,
1416            progressions=progressions_,
1417            render_data=render_data,
1418            character=character_,
1419            character_records=character_records,
1420            profile_records=None,
1421            item_components=item_components,
1422            currency_lookups=currency_lookups,
1423            collectibles=collectibles,
1424            nodes=nodes,
1425        )
1426
1427    def _set_entity_attrs(
1428        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1429    ) -> entity.Entity:
1430        properties = payload[key]
1431        name = typedefs.unknown(properties["name"])
1432        description = typedefs.unknown(properties["description"])
1433
1434        return entity.Entity(
1435            net=self._net,
1436            hash=payload["hash"],
1437            index=payload["index"],
1438            name=name,
1439            description=description,
1440            has_icon=properties["hasIcon"],
1441            icon=assets.Image.default_or_else(properties.get("icon")),
1442        )
1443
1444    def deserialize_inventory_results(
1445        self, payload: typedefs.JSONObject
1446    ) -> iterators.Iterator[entity.SearchableEntity]:
1447        return iterators.Iterator(
1448            [
1449                entity.SearchableEntity(
1450                    net=self._net,
1451                    hash=data["hash"],
1452                    entity_type=data["entityType"],
1453                    weight=data["weight"],
1454                    suggested_words=payload["suggestedWords"],
1455                    name=data["displayProperties"]["name"],
1456                    has_icon=data["displayProperties"]["hasIcon"],
1457                    description=typedefs.unknown(
1458                        data["displayProperties"]["description"]
1459                    ),
1460                    icon=assets.Image(path=data["displayProperties"]["icon"]),
1461                )
1462                for data in payload["results"]["results"]
1463            ]
1464        )
1465
1466    def _deserialize_inventory_item_objects(
1467        self, payload: typedefs.JSONObject
1468    ) -> entity.InventoryEntityObjects:
1469        return entity.InventoryEntityObjects(
1470            action=payload.get("action"),
1471            set_data=payload.get("setData"),
1472            stats=payload.get("stats"),
1473            equipping_block=payload.get("equippingBlock"),
1474            translation_block=payload.get("translationBlock"),
1475            preview=payload.get("preview"),
1476            quality=payload.get("quality"),
1477            value=payload.get("value"),
1478            source_data=payload.get("sourceData"),
1479            objectives=payload.get("objectives"),
1480            plug=payload.get("plug"),
1481            metrics=payload.get("metrics"),
1482            gearset=payload.get("gearset"),
1483            sack=payload.get("sack"),
1484            sockets=payload.get("sockets"),
1485            summary=payload.get("summary"),
1486            talent_gird=payload.get("talentGrid"),
1487            investments_stats=payload.get("investmentStats"),
1488            perks=payload.get("perks"),
1489            animations=payload.get("animations", ()),
1490            links=payload.get("links", ()),
1491        )
1492
1493    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1494        self, payload: typedefs.JSONObject, /
1495    ) -> entity.InventoryEntity:
1496        props = self._set_entity_attrs(payload)
1497        objects = self._deserialize_inventory_item_objects(payload)
1498
1499        collectible_hash: int | None = None
1500        if raw_collectible_hash := payload.get("collectibleHash"):
1501            collectible_hash = int(raw_collectible_hash)
1502
1503        secondary_icon: assets.Image | None = None
1504        if raw_second_icon := payload.get("secondaryIcon"):
1505            secondary_icon = assets.Image(path=raw_second_icon)
1506
1507        secondary_overlay: assets.Image | None = None
1508        if raw_second_overlay := payload.get("secondaryOverlay"):
1509            secondary_overlay = assets.Image(path=raw_second_overlay)
1510
1511        secondary_special: assets.Image | None = None
1512        if raw_second_special := payload.get("secondarySpecial"):
1513            secondary_special = assets.Image(path=raw_second_special)
1514
1515        screenshot: assets.Image | None = None
1516        if raw_screenshot := payload.get("screenshot"):
1517            screenshot = assets.Image(path=raw_screenshot)
1518
1519        watermark_icon: assets.Image | None = None
1520        if raw_watermark_icon := payload.get("iconWatermark"):
1521            watermark_icon = assets.Image(path=raw_watermark_icon)
1522
1523        watermark_shelved: assets.Image | None = None
1524        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1525            watermark_shelved = assets.Image(path=raw_watermark_shelved)
1526
1527        about: str | None = None
1528        if raw_about := payload.get("flavorText"):
1529            about = raw_about
1530
1531        ui_item_style: str | None = None
1532        if raw_ui_style := payload.get("uiItemDisplayStyle"):
1533            ui_item_style = raw_ui_style
1534
1535        tier_and_name: str | None = None
1536        if raw_tier_and_name := payload.get("itemTypeAndTierDisplayName"):
1537            tier_and_name = raw_tier_and_name
1538
1539        type_name: str | None = None
1540        if raw_type_name := payload.get("itemTypeDisplayName"):
1541            type_name = raw_type_name
1542
1543        display_source: str | None = None
1544        if raw_display_source := payload.get("displaySource"):
1545            display_source = raw_display_source
1546
1547        lorehash: int | None = None
1548        if raw_lore_hash := payload.get("loreHash"):
1549            lorehash = int(raw_lore_hash)
1550
1551        summary_hash: int | None = None
1552        if raw_summary_hash := payload.get("summaryItemHash"):
1553            summary_hash = raw_summary_hash
1554
1555        breaker_type_hash: int | None = None
1556        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1557            breaker_type_hash = int(raw_breaker_type_hash)
1558
1559        damage_types: typing.Optional[collections.Sequence[int]] = None
1560        if raw_damage_types := payload.get("damageTypes"):
1561            damage_types = tuple(int(type_) for type_ in raw_damage_types)
1562
1563        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1564        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1565            damagetype_hashes = tuple(int(type_) for type_ in raw_damagetype_hashes)
1566
1567        default_damagetype_hash: int | None = None
1568        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1569            default_damagetype_hash = int(raw_defaultdmg_hash)
1570
1571        emblem_objective_hash: int | None = None
1572        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1573            emblem_objective_hash = int(raw_emblem_obj_hash)
1574
1575        tier_type: enums.TierType | None = None
1576        tier: enums.ItemTier | None = None
1577        bucket_hash: int | None = None
1578        recovery_hash: int | None = None
1579        tier_name: str | None = None
1580        isinstance_item: bool = False
1581        expire_tool_tip: str | None = None
1582        expire_in_orbit_message: str | None = None
1583        suppress_expiration: bool = False
1584        max_stack_size: int | None = None
1585        stack_label: str | None = None
1586
1587        if inventory := payload.get("inventory"):
1588            tier_type = enums.TierType(int(inventory["tierType"]))
1589            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1590            bucket_hash = int(inventory["bucketTypeHash"])
1591            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1592            tier_name = inventory["tierTypeName"]
1593            isinstance_item = inventory["isInstanceItem"]
1594            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1595            max_stack_size = int(inventory["maxStackSize"])
1596
1597            try:
1598                stack_label = inventory["stackUniqueLabel"]
1599            except KeyError:
1600                pass
1601
1602        if "traitHashes" in payload:
1603            trait_hashes = tuple(
1604                int(trait_hash) for trait_hash in payload["traitHashes"]
1605            )
1606        else:
1607            trait_hashes = ()
1608
1609        if "traitIds" in payload:
1610            trait_ids = tuple(trait_id for trait_id in payload["traitIds"])
1611        else:
1612            trait_ids = ()
1613
1614        return entity.InventoryEntity(
1615            net=self._net,
1616            collectible_hash=collectible_hash,
1617            name=props.name,
1618            about=about,
1619            emblem_objective_hash=emblem_objective_hash,
1620            suppress_expiration=suppress_expiration,
1621            max_stack_size=max_stack_size,
1622            stack_label=stack_label,
1623            tier=tier,
1624            tier_type=tier_type,
1625            tier_name=tier_name,
1626            bucket_hash=bucket_hash,
1627            recovery_bucket_hash=recovery_hash,
1628            isinstance_item=isinstance_item,
1629            expire_in_orbit_message=expire_in_orbit_message,
1630            expiration_tooltip=expire_tool_tip,
1631            lore_hash=lorehash,
1632            type_and_tier_name=tier_and_name,
1633            summary_hash=summary_hash,
1634            ui_display_style=ui_item_style,
1635            type_name=type_name,
1636            breaker_type_hash=breaker_type_hash,
1637            description=props.description,
1638            display_source=display_source,
1639            hash=props.hash,
1640            damage_types=damage_types,
1641            index=props.index,
1642            icon=props.icon,
1643            has_icon=props.has_icon,
1644            screenshot=screenshot,
1645            watermark_icon=watermark_icon,
1646            watermark_shelved=watermark_shelved,
1647            secondary_icon=secondary_icon,
1648            secondary_overlay=secondary_overlay,
1649            secondary_special=secondary_special,
1650            type=enums.ItemType(int(payload["itemType"])),
1651            category_hashes=tuple(
1652                int(hash_) for hash_ in payload["itemCategoryHashes"]
1653            ),
1654            item_class=enums.Class(int(payload["classType"])),
1655            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1656            breaker_type=int(payload["breakerType"]),
1657            default_damagetype=int(payload["defaultDamageType"]),
1658            default_damagetype_hash=default_damagetype_hash,
1659            damagetype_hashes=damagetype_hashes,
1660            tooltip_notifications=payload["tooltipNotifications"],
1661            not_transferable=payload["nonTransferrable"],
1662            allow_actions=payload["allowActions"],
1663            is_equippable=payload["equippable"],
1664            objects=objects,
1665            background_colors=payload.get("backgroundColor", {}),
1666            season_hash=payload.get("seasonHash"),
1667            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1668            trait_hashes=trait_hashes,
1669            trait_ids=trait_ids,
1670        )
1671
1672    def deserialize_objective_entity(
1673        self, payload: typedefs.JSONObject, /
1674    ) -> entity.ObjectiveEntity:
1675        props = self._set_entity_attrs(payload)
1676        return entity.ObjectiveEntity(
1677            net=self._net,
1678            hash=props.hash,
1679            index=props.index,
1680            description=props.description,
1681            name=props.name,
1682            has_icon=props.has_icon,
1683            icon=props.icon,
1684            unlock_value_hash=payload["unlockValueHash"],
1685            completion_value=payload["completionValue"],
1686            scope=entity.GatingScope(int(payload["scope"])),
1687            location_hash=payload["locationHash"],
1688            allowed_negative_value=payload["allowNegativeValue"],
1689            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1690            counting_downward=payload["isCountingDownward"],
1691            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1692            progress_description=payload["progressDescription"],
1693            perks=payload["perks"],
1694            stats=payload["stats"],
1695            minimum_visibility=payload["minimumVisibilityThreshold"],
1696            allow_over_completion=payload["allowOvercompletion"],
1697            show_value_style=payload["showValueOnComplete"],
1698            display_only_objective=payload["isDisplayOnlyObjective"],
1699            complete_value_style=entity.ValueUIStyle(
1700                int(payload["completedValueStyle"])
1701            ),
1702            progress_value_style=entity.ValueUIStyle(
1703                int(payload["inProgressValueStyle"])
1704            ),
1705            ui_label=payload["uiLabel"],
1706            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1707        )
1708
1709    def _deserialize_activity_values(
1710        self, payload: typedefs.JSONObject, /
1711    ) -> activity.ActivityValues:
1712        team: int | None = None
1713        if raw_team := payload.get("team"):
1714            team = raw_team["basic"]["value"]
1715        return activity.ActivityValues(
1716            assists=payload["assists"]["basic"]["value"],
1717            deaths=payload["deaths"]["basic"]["value"],
1718            kills=payload["kills"]["basic"]["value"],
1719            is_completed=bool(payload["completed"]["basic"]["value"]),
1720            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1721            efficiency=payload["efficiency"]["basic"]["value"],
1722            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1723            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1724            score=payload["score"]["basic"]["value"],
1725            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1726            team=team,
1727            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1728            fireteam_id=payload["fireteamId"]["basic"]["value"],
1729            start_seconds=payload["startSeconds"]["basic"]["value"],
1730            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1731            player_count=payload["playerCount"]["basic"]["value"],
1732            team_score=payload["teamScore"]["basic"]["value"],
1733        )
1734
1735    def deserialize_activity(
1736        self,
1737        payload: typedefs.JSONObject,
1738        /,
1739    ) -> activity.Activity:
1740        period = time.clean_date(payload["period"])
1741        details = payload["activityDetails"]
1742        ref_id = int(details["referenceId"])
1743        instance_id = int(details["instanceId"])
1744        mode = enums.GameMode(details["mode"])
1745        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1746        is_private = details["isPrivate"]
1747        membership_type = enums.MembershipType(int(details["membershipType"]))
1748
1749        # Since we're using the same fields for post activity method
1750        # this check is required since post activity doesn't values values
1751        values = self._deserialize_activity_values(payload["values"])
1752
1753        return activity.Activity(
1754            net=self._net,
1755            hash=ref_id,
1756            instance_id=instance_id,
1757            mode=mode,
1758            modes=modes,
1759            is_private=is_private,
1760            membership_type=membership_type,
1761            occurred_at=period,
1762            values=values,
1763        )
1764
1765    def deserialize_activities(
1766        self, payload: typedefs.JSONObject
1767    ) -> iterators.Iterator[activity.Activity]:
1768        return iterators.Iterator(
1769            [
1770                self.deserialize_activity(activity_)
1771                for activity_ in payload["activities"]
1772            ]
1773        )
1774
1775    def deserialize_extended_weapon_values(
1776        self, payload: typedefs.JSONObject
1777    ) -> activity.ExtendedWeaponValues:
1778        assists: int | None = None
1779        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1780            assists = raw_assists["basic"]["value"]
1781        assists_damage: int | None = None
1782
1783        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1784            assists_damage = raw_assists_damage["basic"]["value"]
1785
1786        return activity.ExtendedWeaponValues(
1787            reference_id=int(payload["referenceId"]),
1788            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1789            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1790                "value"
1791            ],
1792            assists=assists,
1793            assists_damage=assists_damage,
1794            precision_kills_percentage=(
1795                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1796                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1797                    "displayValue"
1798                ],
1799            ),
1800        )
1801
1802    def _deserialize_extended_values(
1803        self, payload: typedefs.JSONObject
1804    ) -> activity.ExtendedValues:
1805        if raw_weapons := payload.get("weapons"):
1806            weapons = tuple(
1807                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1808            )
1809        else:
1810            weapons = ()
1811
1812        return activity.ExtendedValues(
1813            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1814            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1815            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1816            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1817            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1818            weapons=weapons,
1819        )
1820
1821    def deserialize_post_activity_player(
1822        self, payload: typedefs.JSONObject, /
1823    ) -> activity.PostActivityPlayer:
1824        player = payload["player"]
1825
1826        class_hash: int | None = None
1827        if (class_hash := player.get("classHash")) is not None:
1828            class_hash = class_hash
1829
1830        race_hash: int | None = None
1831        if (race_hash := player.get("raceHash")) is not None:
1832            race_hash = race_hash
1833
1834        gender_hash: int | None = None
1835        if (gender_hash := player.get("genderHash")) is not None:
1836            gender_hash = gender_hash
1837
1838        character_class: str | None = None
1839        if character_class := player.get("characterClass"):
1840            character_class = character_class
1841
1842        character_level: int | None = None
1843        if (character_level := player.get("characterLevel")) is not None:
1844            character_level = character_level
1845
1846        return activity.PostActivityPlayer(
1847            standing=int(payload["standing"]),
1848            score=int(payload["score"]["basic"]["value"]),
1849            character_id=payload["characterId"],
1850            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1851            character_class=character_class,
1852            character_level=character_level,
1853            race_hash=race_hash,
1854            gender_hash=gender_hash,
1855            class_hash=class_hash,
1856            light_level=int(player["lightLevel"]),
1857            emblem_hash=int(player["emblemHash"]),
1858            values=self._deserialize_activity_values(payload["values"]),
1859            extended_values=self._deserialize_extended_values(payload["extended"]),
1860        )
1861
1862    def _deserialize_post_activity_team(
1863        self, payload: typedefs.JSONObject
1864    ) -> activity.PostActivityTeam:
1865        return activity.PostActivityTeam(
1866            id=payload["teamId"],
1867            is_defeated=bool(payload["standing"]["basic"]["value"]),
1868            score=int(payload["score"]["basic"]["value"]),
1869            name=payload["teamName"],
1870        )
1871
1872    def deserialize_post_activity(
1873        self, payload: typedefs.JSONObject
1874    ) -> activity.PostActivity:
1875        period = time.clean_date(payload["period"])
1876        details = payload["activityDetails"]
1877        ref_id = int(details["referenceId"])
1878        instance_id = int(details["instanceId"])
1879        mode = enums.GameMode(details["mode"])
1880        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1881        is_private = details["isPrivate"]
1882        membership_type = enums.MembershipType(int(details["membershipType"]))
1883        return activity.PostActivity(
1884            net=self._net,
1885            hash=ref_id,
1886            membership_type=membership_type,
1887            instance_id=instance_id,
1888            mode=mode,
1889            modes=modes,
1890            is_private=is_private,
1891            occurred_at=period,
1892            starting_phase=int(payload["startingPhaseIndex"]),
1893            players=tuple(
1894                self.deserialize_post_activity_player(player)
1895                for player in payload["entries"]
1896            ),
1897            teams=tuple(
1898                self._deserialize_post_activity_team(team) for team in payload["teams"]
1899            ),
1900        )
1901
1902    def _deserialize_aggregated_activity_values(
1903        self, payload: typedefs.JSONObject
1904    ) -> activity.AggregatedActivityValues:
1905        # This ID is always the same for all aggregated values.
1906        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1907
1908        return activity.AggregatedActivityValues(
1909            id=activity_id,
1910            fastest_completion_time=(
1911                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1912                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1913            ),
1914            completions=int(payload["activityCompletions"]["basic"]["value"]),
1915            kills=int(payload["activityKills"]["basic"]["value"]),
1916            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1917            assists=int(payload["activityAssists"]["basic"]["value"]),
1918            seconds_played=(
1919                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1920                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1921            ),
1922            wins=int(payload["activityWins"]["basic"]["value"]),
1923            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1924            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1925            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1926            best_single_score=int(
1927                payload["activityBestSingleGameScore"]["basic"]["value"]
1928            ),
1929            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1930            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1931            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1932            kd_ratio=float(
1933                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1934            ),
1935            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1936        )
1937
1938    def deserialize_aggregated_activity(
1939        self, payload: typedefs.JSONObject
1940    ) -> activity.AggregatedActivity:
1941        return activity.AggregatedActivity(
1942            hash=int(payload["activityHash"]),
1943            values=self._deserialize_aggregated_activity_values(payload["values"]),
1944        )
1945
1946    def deserialize_aggregated_activities(
1947        self, payload: typedefs.JSONObject
1948    ) -> iterators.Iterator[activity.AggregatedActivity]:
1949        return iterators.Iterator(
1950            [
1951                self.deserialize_aggregated_activity(activity)
1952                for activity in payload["activities"]
1953            ]
1954        )
1955
1956    def deserialize_linked_profiles(
1957        self, payload: typedefs.JSONObject
1958    ) -> profile.LinkedProfile:
1959        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
1960
1961        if raw_profile := payload.get("profiles"):
1962            profiles = tuple(
1963                self.deserialize_destiny_membership(p) for p in raw_profile
1964            )
1965        else:
1966            profiles = ()
1967
1968        error_profiles = ()
1969        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
1970            for raw_error_p in raw_profiles_with_errors:
1971                if "infoCard" in raw_error_p:
1972                    error_profiles = tuple(
1973                        self.deserialize_destiny_membership(error_p)
1974                        for error_p in raw_error_p
1975                    )
1976
1977        return profile.LinkedProfile(
1978            bungie_user=bungie_user,
1979            profiles=profiles,
1980            profiles_with_errors=error_profiles,
1981        )
1982
1983    def deserialize_clan_banners(
1984        self, payload: typedefs.JSONObject
1985    ) -> collections.Sequence[clans.ClanBanner]:
1986        if banners := payload.get("clanBannerDecals"):
1987            banner_obj = tuple(
1988                clans.ClanBanner(
1989                    id=int(k),
1990                    foreground=assets.Image(path=v["foregroundPath"]),
1991                    background=assets.Image(path=v["backgroundPath"]),
1992                )
1993                for k, v in banners.items()
1994            )
1995        else:
1996            banner_obj = ()
1997        return banner_obj
1998
1999    def deserialize_public_milestone_content(
2000        self, payload: typedefs.JSONObject
2001    ) -> milestones.MilestoneContent:
2002        if raw_categories := payload.get("itemCategories"):
2003            items_categories = tuple(
2004                milestones.MilestoneItems(
2005                    title=item["title"], hashes=item["itemHashes"]
2006                )
2007                for item in raw_categories
2008            )
2009        else:
2010            items_categories = ()
2011
2012        return milestones.MilestoneContent(
2013            about=typedefs.unknown(payload["about"]),
2014            status=typedefs.unknown(payload["status"]),
2015            tips=payload.get("tips", ()),
2016            items=items_categories,
2017        )
2018
2019    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2020        bungie_user: user.BungieUser | None = None
2021
2022        if raw_bungie_user := payload.get("bungieNetUser"):
2023            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2024
2025        return friends.Friend(
2026            net=self._net,
2027            id=int(payload["lastSeenAsMembershipId"]),
2028            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
2029            code=payload.get("bungieGlobalDisplayNameCode"),
2030            relationship=enums.Relationship(payload["relationship"]),
2031            user=bungie_user,
2032            online_status=enums.Presence(payload["onlineStatus"]),
2033            online_title=payload["onlineTitle"],
2034            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2035        )
2036
2037    def deserialize_friends(
2038        self, payload: typedefs.JSONObject
2039    ) -> collections.Sequence[friends.Friend]:
2040        return tuple(self.deserialize_friend(friend) for friend in payload["friends"])
2041
2042    def deserialize_friend_requests(
2043        self, payload: typedefs.JSONObject
2044    ) -> friends.FriendRequestView:
2045        if raw_incoming_requests := payload.get("incomingRequests"):
2046            incoming = tuple(
2047                self.deserialize_friend(incoming_request)
2048                for incoming_request in raw_incoming_requests
2049            )
2050        else:
2051            incoming = ()
2052
2053        if raw_outgoing_requests := payload.get("outgoingRequests"):
2054            outgoing = tuple(
2055                self.deserialize_friend(outgoing_request)
2056                for outgoing_request in raw_outgoing_requests
2057            )
2058        else:
2059            outgoing = ()
2060
2061        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2062
2063    def _set_fireteam_fields(
2064        self, payload: typedefs.JSONObject, total_results: int | None = None
2065    ) -> fireteams.Fireteam:
2066        activity_type = fireteams.FireteamActivity(payload["activityType"])
2067        return fireteams.Fireteam(
2068            id=int(payload["fireteamId"]),
2069            group_id=int(payload["groupId"]),
2070            platform=fireteams.FireteamPlatform(payload["platform"]),
2071            is_immediate=payload["isImmediate"],
2072            activity_type=activity_type,
2073            owner_id=int(payload["ownerMembershipId"]),
2074            player_slot_count=payload["playerSlotCount"],
2075            available_player_slots=payload["availablePlayerSlotCount"],
2076            available_alternate_slots=payload["availableAlternateSlotCount"],
2077            title=payload["title"],
2078            date_created=time.clean_date(payload["dateCreated"]),
2079            is_public=payload["isPublic"],
2080            locale=fireteams.FireteamLanguage(payload["locale"]),
2081            is_valid=payload["isValid"],
2082            last_modified=time.clean_date(payload["datePlayerModified"]),
2083            date_modified=time.clean_date(payload["dateModified"])
2084            if "dateModified" in payload
2085            else None,
2086            scheduled_time=time.clean_date(payload["scheduledTime"])
2087            if "scheduledTime" in payload
2088            else None,
2089            total_results=total_results or 0,
2090        )
2091
2092    def deserialize_fireteams(
2093        self, payload: typedefs.JSONObject
2094    ) -> collections.Sequence[fireteams.Fireteam]:
2095        if "results" in payload:
2096            fireteams_ = tuple(
2097                self._set_fireteam_fields(
2098                    elem, total_results=int(payload["totalResults"])
2099                )
2100                for elem in payload["results"]
2101            )
2102        else:
2103            fireteams_ = ()
2104        return fireteams_
2105
2106    def deserialize_fireteam_destiny_users(
2107        self, payload: typedefs.JSONObject
2108    ) -> fireteams.FireteamUser:
2109        destiny_obj = self.deserialize_destiny_membership(payload)
2110        return fireteams.FireteamUser(
2111            net=self._net,
2112            id=destiny_obj.id,
2113            code=destiny_obj.code,
2114            icon=destiny_obj.icon,
2115            types=destiny_obj.types,
2116            type=destiny_obj.type,
2117            is_public=destiny_obj.is_public,
2118            crossave_override=destiny_obj.crossave_override,
2119            name=destiny_obj.name,
2120            last_seen_name=destiny_obj.last_seen_name,
2121            fireteam_display_name=payload["FireteamDisplayName"],
2122            fireteam_membership_id=enums.MembershipType(
2123                payload["FireteamMembershipType"]
2124            ),
2125        )
2126
2127    def deserialize_fireteam_members(
2128        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2129    ) -> collections.Sequence[fireteams.FireteamMember]:
2130        members_: list[fireteams.FireteamMember] = []
2131        if members := payload.get("Members" if not alternatives else "Alternates"):
2132            for member in members:
2133                bungie_fields = self.deserialize_partial_bungie_user(member)
2134                members_fields = fireteams.FireteamMember(
2135                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2136                    has_microphone=member["hasMicrophone"],
2137                    character_id=int(member["characterId"]),
2138                    date_joined=time.clean_date(member["dateJoined"]),
2139                    last_platform_invite_date=time.clean_date(
2140                        member["lastPlatformInviteAttemptDate"]
2141                    ),
2142                    last_platform_invite_result=int(
2143                        member["lastPlatformInviteAttemptResult"]
2144                    ),
2145                    net=self._net,
2146                    name=bungie_fields.name,
2147                    id=bungie_fields.id,
2148                    icon=bungie_fields.icon,
2149                    is_public=bungie_fields.is_public,
2150                    crossave_override=bungie_fields.crossave_override,
2151                    types=bungie_fields.types,
2152                    type=bungie_fields.type,
2153                )
2154                members_.append(members_fields)
2155        return tuple(members_)
2156
2157    def deserialize_available_fireteam(
2158        self, payload: typedefs.JSONObject
2159    ) -> fireteams.AvailableFireteam:
2160        fields = self._set_fireteam_fields(payload["Summary"])
2161        return fireteams.AvailableFireteam(
2162            id=fields.id,
2163            group_id=fields.group_id,
2164            platform=fields.platform,
2165            activity_type=fields.activity_type,
2166            is_immediate=fields.is_immediate,
2167            is_public=fields.is_public,
2168            is_valid=fields.is_valid,
2169            owner_id=fields.owner_id,
2170            player_slot_count=fields.player_slot_count,
2171            available_player_slots=fields.available_player_slots,
2172            available_alternate_slots=fields.available_alternate_slots,
2173            title=fields.title,
2174            date_created=fields.date_created,
2175            locale=fields.locale,
2176            last_modified=fields.last_modified,
2177            total_results=fields.total_results,
2178            scheduled_time=fields.scheduled_time,
2179            date_modified=fields.date_modified,
2180            members=self.deserialize_fireteam_members(payload),
2181            alternatives=self.deserialize_fireteam_members(payload, alternatives=True),
2182        )
2183
2184    def deserialize_available_fireteams(
2185        self, data: typedefs.JSONObject
2186    ) -> collections.Sequence[fireteams.AvailableFireteam]:
2187        if raw_results := data.get("results"):
2188            fireteam_results = tuple(
2189                self.deserialize_available_fireteam(f) for f in raw_results
2190            )
2191        else:
2192            fireteam_results = ()
2193        return fireteam_results
2194
2195    def deserialize_fireteam_party(
2196        self, payload: typedefs.JSONObject
2197    ) -> fireteams.FireteamParty:
2198        last_destination_hash: int | None = None
2199        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2200            last_destination_hash = int(raw_dest_hash)
2201
2202        return fireteams.FireteamParty(
2203            members=tuple(
2204                self._deserialize_fireteam_party_member(member)
2205                for member in payload["partyMembers"]
2206            ),
2207            activity=self._deserialize_fireteam_party_current_activity(
2208                payload["currentActivity"]
2209            ),
2210            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2211            last_destination_hash=last_destination_hash,
2212            tracking=payload["tracking"],
2213        )
2214
2215    def _deserialize_fireteam_party_member(
2216        self, payload: typedefs.JSONObject
2217    ) -> fireteams.FireteamPartyMember:
2218        status = fireteams.FireteamPartyMemberState(payload["status"])
2219
2220        return fireteams.FireteamPartyMember(
2221            membership_id=int(payload["membershipId"]),
2222            emblem_hash=int(payload["emblemHash"]),
2223            status=status,
2224            display_name=payload["displayName"] if payload["displayName"] else None,
2225        )
2226
2227    def _deserialize_fireteam_party_current_activity(
2228        self, payload: typedefs.JSONObject
2229    ) -> fireteams.FireteamPartyCurrentActivity:
2230        start_date: datetime.datetime | None = None
2231        if raw_start_date := payload.get("startTime"):
2232            start_date = time.clean_date(raw_start_date)
2233
2234        end_date: datetime.datetime | None = None
2235        if raw_end_date := payload.get("endTime"):
2236            end_date = time.clean_date(raw_end_date)
2237        return fireteams.FireteamPartyCurrentActivity(
2238            start_time=start_date,
2239            end_time=end_date,
2240            score=float(payload["score"]),
2241            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2242            opponents_count=int(payload["numberOfOpponents"]),
2243            player_count=int(payload["numberOfPlayers"]),
2244        )
2245
2246    def _deserialize_fireteam_party_settings(
2247        self, payload: typedefs.JSONObject
2248    ) -> fireteams.FireteamPartySettings:
2249        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2250        return fireteams.FireteamPartySettings(
2251            open_slots=int(payload["openSlots"]),
2252            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2253            closed_reasons=closed_reasons,
2254        )
2255
2256    def deserialize_seasonal_artifact(
2257        self, payload: typedefs.JSONObject
2258    ) -> season.Artifact:
2259        raw_artifact = payload["seasonalArtifact"]
2260
2261        points = raw_artifact["pointProgression"]
2262        points_prog = progressions.Progression(
2263            hash=points["progressionHash"],
2264            level=points["level"],
2265            cap=points["levelCap"],
2266            daily_limit=points["dailyLimit"],
2267            weekly_limit=points["weeklyLimit"],
2268            current_progress=points["currentProgress"],
2269            daily_progress=points["dailyProgress"],
2270            needed=points["progressToNextLevel"],
2271            next_level=points["nextLevelAt"],
2272        )
2273
2274        bonus = raw_artifact["powerBonusProgression"]
2275        power_bonus_prog = progressions.Progression(
2276            hash=bonus["progressionHash"],
2277            level=bonus["level"],
2278            cap=bonus["levelCap"],
2279            daily_limit=bonus["dailyLimit"],
2280            weekly_limit=bonus["weeklyLimit"],
2281            current_progress=bonus["currentProgress"],
2282            daily_progress=bonus["dailyProgress"],
2283            needed=bonus["progressToNextLevel"],
2284            next_level=bonus["nextLevelAt"],
2285        )
2286        return season.Artifact(
2287            hash=raw_artifact["artifactHash"],
2288            power_bonus=raw_artifact["powerBonus"],
2289            acquired_points=raw_artifact["pointsAcquired"],
2290            bonus=power_bonus_prog,
2291            points=points_prog,
2292        )
2293
2294    def deserialize_profile_progression(
2295        self, payload: typedefs.JSONObject
2296    ) -> profile.ProfileProgression:
2297        return profile.ProfileProgression(
2298            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2299            checklist={
2300                int(check_id): checklists
2301                for check_id, checklists in payload["data"]["checklists"].items()
2302            },
2303        )
2304
2305    def deserialize_instanced_item(
2306        self, payload: typedefs.JSONObject
2307    ) -> items.ItemInstance:
2308        damage_type_hash: int | None = None
2309        if raw_damagetype_hash := payload.get("damageTypeHash"):
2310            damage_type_hash = int(raw_damagetype_hash)
2311
2312        required_hashes: typing.Optional[collections.Collection[int]] = None
2313        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2314            required_hashes = tuple(int(raw_hash) for raw_hash in raw_required_hashes)
2315
2316        breaker_type: items.ItemBreakerType | None = None
2317        if raw_break_type := payload.get("breakerType"):
2318            breaker_type = items.ItemBreakerType(int(raw_break_type))
2319
2320        breaker_type_hash: int | None = None
2321        if raw_break_type_hash := payload.get("breakerTypeHash"):
2322            breaker_type_hash = int(raw_break_type_hash)
2323
2324        energy: items.ItemEnergy | None = None
2325        if raw_energy := payload.get("energy"):
2326            energy = self.deserialize_item_energy(raw_energy)
2327
2328        primary_stats = None
2329        if raw_primary_stats := payload.get("primaryStat"):
2330            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2331
2332        return items.ItemInstance(
2333            damage_type=enums.DamageType(int(payload["damageType"])),
2334            damage_type_hash=damage_type_hash,
2335            primary_stat=primary_stats,
2336            item_level=int(payload["itemLevel"]),
2337            quality=int(payload["quality"]),
2338            is_equipped=payload["isEquipped"],
2339            can_equip=payload["canEquip"],
2340            equip_required_level=int(payload["equipRequiredLevel"]),
2341            required_equip_unlock_hashes=required_hashes,
2342            cant_equip_reason=int(payload["cannotEquipReason"]),
2343            breaker_type=breaker_type,
2344            breaker_type_hash=breaker_type_hash,
2345            energy=energy,
2346        )
2347
2348    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2349        energy_hash: int | None = None
2350        if raw_energy_hash := payload.get("energyTypeHash"):
2351            energy_hash = int(raw_energy_hash)
2352
2353        return items.ItemEnergy(
2354            hash=energy_hash,
2355            type=items.ItemEnergyType(int(payload["energyType"])),
2356            capacity=int(payload["energyCapacity"]),
2357            used_energy=int(payload["energyUsed"]),
2358            unused_energy=int(payload["energyUnused"]),
2359        )
2360
2361    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2362        perk_hash: int | None = None
2363        if raw_perk_hash := payload.get("perkHash"):
2364            perk_hash = int(raw_perk_hash)
2365
2366        return items.ItemPerk(
2367            hash=perk_hash,
2368            icon=assets.Image(path=payload["iconPath"]),
2369            is_active=payload["isActive"],
2370            is_visible=payload["visible"],
2371        )
2372
2373    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2374        plug_hash: int | None = None
2375        if raw_plug_hash := payload.get("plugHash"):
2376            plug_hash = int(raw_plug_hash)
2377
2378        enable_fail_indexes: collections.Sequence[int] | None = None
2379        if raw_indexes := payload.get("enableFailIndexes"):
2380            enable_fail_indexes = tuple(int(index) for index in raw_indexes)
2381
2382        return items.ItemSocket(
2383            plug_hash=plug_hash,
2384            is_enabled=payload["isEnabled"],
2385            enable_fail_indexes=enable_fail_indexes,
2386            is_visible=payload.get("visible"),
2387        )
2388
2389    def deserialize_item_stats_view(
2390        self, payload: typedefs.JSONObject
2391    ) -> items.ItemStatsView:
2392        return items.ItemStatsView(
2393            stat_hash=payload.get("statHash"), value=payload.get("value")
2394        )
2395
2396    def deserialize_plug_item_state(
2397        self, payload: typedefs.JSONObject
2398    ) -> items.PlugItemState:
2399        item_hash: int | None = None
2400        if raw_item_hash := payload.get("plugItemHash"):
2401            item_hash = int(raw_item_hash)
2402
2403        insert_fail_indexes: collections.Sequence[int] | None = None
2404        if raw_fail_indexes := payload.get("insertFailIndexes"):
2405            insert_fail_indexes = tuple(int(k) for k in raw_fail_indexes)
2406
2407        enable_fail_indexes: collections.Sequence[int] | None = None
2408        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2409            enable_fail_indexes = tuple(int(k) for k in raw_enabled_indexes)
2410
2411        return items.PlugItemState(
2412            item_hash=item_hash,
2413            insert_fail_indexes=insert_fail_indexes,
2414            enable_fail_indexes=enable_fail_indexes,
2415            is_enabled=payload["enabled"],
2416            can_insert=payload["canInsert"],
2417        )

The base deserialization factory class for all aiobungie objects.

This entity factory is used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
69    def __init__(self, net: traits.Netrunner) -> None:
70        self._net = net
def deserialize_bungie_user( self, data: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
72    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
73        return user.BungieUser(
74            id=int(data["membershipId"]),
75            created_at=time.clean_date(data["firstAccess"]),
76            name=data.get("cachedBungieGlobalDisplayName"),
77            is_deleted=data["isDeleted"],
78            about=data["about"],
79            updated_at=time.clean_date(data["lastUpdate"]),
80            psn_name=data.get("psnDisplayName", None),
81            stadia_name=data.get("stadiaDisplayName", None),
82            steam_name=data.get("steamDisplayName", None),
83            twitch_name=data.get("twitchDisplayName", None),
84            blizzard_name=data.get("blizzardDisplayName", None),
85            status=data["statusText"],
86            locale=data["locale"],
87            picture=assets.Image(path=data["profilePicturePath"]),
88            code=data.get("cachedBungieGlobalDisplayNameCode", None),
89            unique_name=data.get("uniqueName", None),
90            theme_id=int(data["profileTheme"]),
91            show_activity=bool(data["showActivity"]),
92            theme_name=data["profileThemeName"],
93            display_title=data["userTitleDisplay"],
94        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 96    def deserialize_partial_bungie_user(
 97        self, payload: typedefs.JSONObject
 98    ) -> user.PartialBungieUser:
 99        return user.PartialBungieUser(
100            net=self._net,
101            types=tuple(
102                enums.MembershipType(type_)
103                for type_ in payload.get("applicableMembershipTypes", ())
104            ),
105            name=payload.get("displayName"),
106            id=int(payload["membershipId"]),
107            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
108            is_public=payload["isPublic"],
109            icon=assets.Image(path=payload.get("iconPath", "")),
110            type=enums.MembershipType(payload["membershipType"]),
111        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
113    def deserialize_destiny_membership(
114        self, payload: typedefs.JSONObject
115    ) -> user.DestinyMembership:
116        name: str | None = None
117        if (raw_name := payload.get("bungieGlobalDisplayName")) is not None:
118            name = typedefs.unknown(raw_name)
119
120        return user.DestinyMembership(
121            net=self._net,
122            id=int(payload["membershipId"]),
123            name=name,
124            code=payload.get("bungieGlobalDisplayNameCode", None),
125            last_seen_name=payload.get("LastSeenDisplayName")
126            or payload.get("displayName")  # noqa: W503
127            or "",  # noqa: W503
128            type=enums.MembershipType(payload["membershipType"]),
129            is_public=payload["isPublic"],
130            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
131            icon=assets.Image(path=payload.get("iconPath", "")),
132            types=tuple(
133                enums.MembershipType(type_)
134                for type_ in payload.get("applicableMembershipTypes", ())
135            ),
136        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
138    def deserialize_destiny_memberships(
139        self, data: typedefs.JSONArray
140    ) -> collections.Sequence[user.DestinyMembership]:
141        return tuple(
142            self.deserialize_destiny_membership(membership) for membership in data
143        )

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user( self, data: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.User:
145    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
146        primary_membership_id: int | None = None
147        if raw_primary_id := data.get("primaryMembershipId"):
148            primary_membership_id = int(raw_primary_id)
149
150        return user.User(
151            bungie_user=self.deserialize_bungie_user(data["bungieNetUser"]),
152            memberships=self.deserialize_destiny_memberships(
153                data["destinyMemberships"]
154            ),
155            primary_membership_id=primary_membership_id,
156        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
158    def deserialize_searched_user(
159        self, payload: typedefs.JSONObject
160    ) -> user.SearchableDestinyUser:
161        code: int | None = None
162        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
163            code = int(raw_code)
164
165        bungie_id: int | None = None
166        if raw_bungie_id := payload.get("bungieNetMembershipId"):
167            bungie_id = int(raw_bungie_id)
168
169        return user.SearchableDestinyUser(
170            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
171            code=code,
172            bungie_id=bungie_id,
173            memberships=self.deserialize_destiny_memberships(
174                payload["destinyMemberships"]
175            ),
176        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
178    def deserialize_user_credentials(
179        self, payload: typedefs.JSONArray
180    ) -> collections.Sequence[user.UserCredentials]:
181        return tuple(
182            user.UserCredentials(
183                type=enums.CredentialType(int(creds["credentialType"])),
184                display_name=creds["credentialDisplayName"],
185                is_public=creds["isPublic"],
186                self_as_string=creds.get("credentialAsString"),
187            )
188            for creds in payload
189        )

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
def deserialize_user_themes( self, payload: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
191    def deserialize_user_themes(
192        self, payload: typedefs.JSONArray
193    ) -> collections.Sequence[user.UserThemes]:
194        return tuple(
195            user.UserThemes(
196                id=int(entry["userThemeId"]),
197                name=entry["userThemeName"] if "userThemeName" in entry else None,
198                description=entry["userThemeDescription"]
199                if "userThemeDescription" in entry
200                else None,
201            )
202            for entry in payload
203        )

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.clans.Clan:
254    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
255        current_user_map: collections.Mapping[str, clans.ClanMember] | None = None
256        if raw_current_user := payload.get("currentUserMemberMap"):
257            # This will get populated if only it was a GroupsV2.GroupResponse.
258            # GroupsV2.GetGroupsForMemberResponse doesn't have this field.
259            current_user_map = {
260                membership_type: self.deserialize_clan_member(membership)
261                for membership_type, membership in raw_current_user.items()
262            }
263
264        return self._deserialize_group_details(
265            data=payload["detail"],
266            clan_founder=self.deserialize_clan_member(payload["founder"]),
267            current_user_memberships=current_user_map,
268        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
270    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
271        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
272        return clans.ClanMember(
273            net=self._net,
274            last_seen_name=destiny_user.last_seen_name,
275            id=destiny_user.id,
276            name=destiny_user.name,
277            icon=destiny_user.icon,
278            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
279            group_id=int(data["groupId"]),
280            joined_at=time.clean_date(data["joinDate"]),
281            types=destiny_user.types,
282            is_public=destiny_user.is_public,
283            type=destiny_user.type,
284            code=destiny_user.code,
285            is_online=data["isOnline"],
286            crossave_override=destiny_user.crossave_override,
287            bungie_user=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
288            if "bungieNetUserInfo" in data
289            else None,
290            member_type=enums.ClanMemberType(int(data["memberType"])),
291        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: collections.abc.Mapping[str, typing.Any], /) -> Iterator[aiobungie.crates.clans.ClanMember]:
293    def deserialize_clan_members(
294        self, data: typedefs.JSONObject, /
295    ) -> iterators.Iterator[clans.ClanMember]:
296        return iterators.Iterator(
297            self.deserialize_clan_member(member) for member in data["results"]
298        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
300    def deserialize_group_member(
301        self, payload: typedefs.JSONObject
302    ) -> clans.GroupMember:
303        member = payload["member"]
304        return clans.GroupMember(
305            net=self._net,
306            join_date=time.clean_date(member["joinDate"]),
307            group_id=int(member["groupId"]),
308            member_type=enums.ClanMemberType(member["memberType"]),
309            is_online=member["isOnline"],
310            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
311            inactive_memberships=payload.get("areAllMembershipsInactive", None),
312            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
313            group=self._deserialize_group_details(payload["group"]),
314        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
328    def deserialize_clan_conversations(
329        self, payload: typedefs.JSONArray
330    ) -> collections.Sequence[clans.ClanConversation]:
331        return tuple(self._deserialize_clan_conversation(conv) for conv in payload)

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
333    def deserialize_app_owner(
334        self, payload: typedefs.JSONObject
335    ) -> application.ApplicationOwner:
336        return application.ApplicationOwner(
337            net=self._net,
338            name=payload.get("bungieGlobalDisplayName"),
339            id=int(payload["membershipId"]),
340            type=enums.MembershipType(payload["membershipType"]),
341            icon=assets.Image(path=payload["iconPath"]),
342            is_public=payload["isPublic"],
343            code=payload.get("bungieGlobalDisplayNameCode", None),
344        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.application.Application:
346    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
347        return application.Application(
348            id=int(payload["applicationId"]),
349            name=payload["name"],
350            link=payload["link"],
351            status=payload["status"],
352            redirect_url=payload.get("redirectUrl", None),
353            created_at=time.clean_date(payload["creationDate"]),
354            published_at=time.clean_date(payload["firstPublished"]),
355            owner=self.deserialize_app_owner(payload["team"][0]["user"]),
356            scope=payload.get("scope"),
357        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.profile.Profile:
383    def deserialize_profile(self, payload: typedefs.JSONObject, /) -> profile.Profile:
384        payload = payload["data"]
385        id = int(payload["userInfo"]["membershipId"])
386        name = payload["userInfo"]["displayName"]
387        is_public = payload["userInfo"]["isPublic"]
388        type = enums.MembershipType(payload["userInfo"]["membershipType"])
389        last_played = time.clean_date(payload["dateLastPlayed"])
390        character_ids = tuple(int(cid) for cid in payload["characterIds"])
391        power_cap = payload["currentSeasonRewardPowerCap"]
392
393        return profile.Profile(
394            id=int(id),
395            name=name,
396            is_public=is_public,
397            type=type,
398            last_played=last_played,
399            character_ids=character_ids,
400            power_cap=power_cap,
401            net=self._net,
402        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
404    def deserialize_profile_item(
405        self, payload: typedefs.JSONObject
406    ) -> profile.ProfileItemImpl:
407        instance_id: int | None = None
408        if raw_instance_id := payload.get("itemInstanceId"):
409            instance_id = int(raw_instance_id)
410
411        version_number: int | None = None
412        if raw_version := payload.get("versionNumber"):
413            version_number = int(raw_version)
414
415        transfer_status = enums.TransferStatus(payload["transferStatus"])
416
417        return profile.ProfileItemImpl(
418            net=self._net,
419            hash=payload["itemHash"],
420            quantity=payload["quantity"],
421            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
422            location=enums.ItemLocation(payload["location"]),
423            bucket=payload["bucketHash"],
424            transfer_status=transfer_status,
425            lockable=payload["lockable"],
426            state=enums.ItemState(payload["state"]),
427            dismantle_permissions=payload["dismantlePermission"],
428            is_wrapper=payload["isWrapper"],
429            instance_id=instance_id,
430            version_number=version_number,
431            ornament_id=payload.get("overrideStyleItemHash"),
432        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.records.Objective:
434    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
435        return records.Objective(
436            net=self._net,
437            hash=payload["objectiveHash"],
438            visible=payload["visible"],
439            complete=payload["complete"],
440            completion_value=payload["completionValue"],
441            progress=payload.get("progress"),
442            destination_hash=payload.get("destinationHash"),
443            activity_hash=payload.get("activityHash"),
444        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: collections.abc.Mapping[str, typing.Any], scores: aiobungie.crates.records.RecordScores | None = None, **nodes: int) -> aiobungie.crates.records.Record:
447    def deserialize_records(
448        self,
449        payload: typedefs.JSONObject,
450        scores: records.RecordScores | None = None,
451        **nodes: int,
452    ) -> records.Record:
453        objectives: collections.Sequence[records.Objective] | None = None
454        interval_objectives: collections.Sequence[records.Objective] | None = None
455        record_state: records.RecordState | int
456
457        record_state = records.RecordState(payload["state"])
458
459        if raw_objs := payload.get("objectives"):
460            objectives = tuple(self.deserialize_objectives(obj) for obj in raw_objs)
461
462        if raw_interval_objs := payload.get("intervalObjectives"):
463            interval_objectives = tuple(
464                self.deserialize_objectives(obj) for obj in raw_interval_objs
465            )
466
467        return records.Record(
468            scores=scores,
469            categories_node_hash=nodes.get("categories_hash"),
470            seals_node_hash=nodes.get("seals_hash"),
471            state=record_state,
472            objectives=objectives,
473            interval_objectives=interval_objectives,
474            redeemed_count=payload.get("intervalsRedeemedCount", 0),
475            completion_times=payload.get("completedCount", None),
476            reward_visibility=payload.get("rewardVisibility"),
477        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (records.RecordScores | None): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: collections.abc.Mapping[str, typing.Any], scores: aiobungie.crates.records.RecordScores | None = None, record_hashes: collections.abc.Sequence[int] = ()) -> aiobungie.crates.records.CharacterRecord:
479    def deserialize_character_records(
480        self,
481        payload: typedefs.JSONObject,
482        scores: records.RecordScores | None = None,
483        record_hashes: collections.Sequence[int] = (),
484    ) -> records.CharacterRecord:
485        record = self.deserialize_records(payload, scores)
486        return records.CharacterRecord(
487            scores=scores,
488            categories_node_hash=record.categories_node_hash,
489            seals_node_hash=record.seals_node_hash,
490            state=record.state,
491            objectives=record.objectives,
492            interval_objectives=record.interval_objectives,
493            redeemed_count=payload.get("intervalsRedeemedCount", 0),
494            completion_times=payload.get("completedCount"),
495            reward_visibility=payload.get("rewardVisibility"),
496            record_hashes=record_hashes,
497        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.Dye:
499    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
500        return character.Dye(
501            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
502        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
504    def deserialize_character_customization(
505        self, payload: typedefs.JSONObject
506    ) -> character.CustomizationOptions:
507        return character.CustomizationOptions(
508            personality=payload["personality"],
509            face=payload["face"],
510            skin_color=payload["skinColor"],
511            lip_color=payload["lipColor"],
512            eye_color=payload["eyeColor"],
513            hair_colors=payload.get("hairColors", ()),
514            feature_colors=payload.get("featureColors", ()),
515            decal_color=payload["decalColor"],
516            wear_helmet=payload["wearHelmet"],
517            hair_index=payload["hairIndex"],
518            feature_index=payload["featureIndex"],
519            decal_index=payload["decalIndex"],
520        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
522    def deserialize_character_minimal_equipments(
523        self, payload: typedefs.JSONObject
524    ) -> character.MinimalEquipments:
525        if raw_dyes := payload.get("dyes"):
526            dyes = tuple(self.deserialize_character_dye(dye) for dye in raw_dyes)
527        else:
528            dyes = ()
529
530        return character.MinimalEquipments(
531            net=self._net, item_hash=payload["itemHash"], dyes=dyes
532        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
534    def deserialize_character_render_data(
535        self, payload: typedefs.JSONObject, /
536    ) -> character.RenderedData:
537        return character.RenderedData(
538            net=self._net,
539            customization=self.deserialize_character_customization(
540                payload["customization"]
541            ),
542            custom_dyes=tuple(
543                self.deserialize_character_dye(dye)
544                for dye in payload["customDyes"]
545                if dye
546            ),
547            equipment=tuple(
548                self.deserialize_character_minimal_equipments(equipment)
549                for equipment in payload["peerView"]["equipment"]
550            ),
551        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
553    def deserialize_available_activity(
554        self, payload: typedefs.JSONObject
555    ) -> activity.AvailableActivity:
556        return activity.AvailableActivity(
557            hash=payload["activityHash"],
558            is_new=payload["isNew"],
559            is_completed=payload["isCompleted"],
560            is_visible=payload["isVisible"],
561            display_level=payload.get("displayLevel"),
562            recommended_light=payload.get("recommendedLight"),
563            difficulty=activity.Difficulty(payload["difficultyTier"]),
564            can_join=payload["canJoin"],
565            can_lead=payload["canLead"],
566        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
568    def deserialize_character_activity(
569        self, payload: typedefs.JSONObject
570    ) -> activity.CharacterActivity:
571        current_mode: enums.GameMode | None = None
572        if raw_current_mode := payload.get("currentActivityModeType"):
573            current_mode = enums.GameMode(raw_current_mode)
574
575        if raw_current_modes := payload.get("currentActivityModeTypes"):
576            current_mode_types = tuple(
577                enums.GameMode(type_) for type_ in raw_current_modes
578            )
579        else:
580            current_mode_types = ()
581
582        return activity.CharacterActivity(
583            date_started=time.clean_date(payload["dateActivityStarted"]),
584            current_hash=payload["currentActivityHash"],
585            current_mode_hash=payload["currentActivityModeHash"],
586            current_mode=current_mode,
587            current_mode_hashes=payload.get("currentActivityModeHashes", ()),
588            current_mode_types=current_mode_types,
589            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
590            last_story_hash=payload["lastCompletedStoryHash"],
591            available_activities=tuple(
592                self.deserialize_available_activity(activity_)
593                for activity_ in payload["availableActivities"]
594            ),
595        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: collections.abc.Mapping[str, typing.Any], /) -> collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]:
597    def deserialize_profile_items(
598        self, payload: typedefs.JSONObject, /
599    ) -> collections.Sequence[profile.ProfileItemImpl]:
600        return tuple(self.deserialize_profile_item(item) for item in payload["items"])

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
643    def deserialize_progressions(
644        self, payload: typedefs.JSONObject
645    ) -> progressions.Progression:
646        return progressions.Progression(
647            hash=int(payload["progressionHash"]),
648            level=int(payload["level"]),
649            cap=int(payload["levelCap"]),
650            daily_limit=int(payload["dailyLimit"]),
651            weekly_limit=int(payload["weeklyLimit"]),
652            current_progress=int(payload["currentProgress"]),
653            daily_progress=int(payload["dailyProgress"]),
654            needed=int(payload["progressToNextLevel"]),
655            next_level=int(payload["nextLevelAt"]),
656        )
def deserialize_milestone( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
741    def deserialize_milestone(
742        self, payload: typedefs.JSONObject
743    ) -> milestones.Milestone:
744        start_date: datetime.datetime | None = None
745        if raw_start_date := payload.get("startDate"):
746            start_date = time.clean_date(raw_start_date)
747
748        end_date: datetime.datetime | None = None
749        if raw_end_date := payload.get("endDate"):
750            end_date = time.clean_date(raw_end_date)
751
752        rewards: collections.Collection[milestones.MilestoneReward] | None = None
753        if raw_rewards := payload.get("rewards"):
754            rewards = tuple(
755                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
756            )
757
758        activities: collections.Sequence[milestones.MilestoneActivity] | None = None
759        if raw_activities := payload.get("activities"):
760            activities = tuple(
761                self._deserialize_milestone_activity(active)
762                for active in raw_activities
763            )
764
765        quests: collections.Sequence[milestones.MilestoneQuest] | None = None
766        if raw_quests := payload.get("availableQuests"):
767            quests = tuple(
768                self._deserialize_milestone_available_quest(quest)
769                for quest in raw_quests
770            )
771
772        vendors: collections.Sequence[milestones.MilestoneVendor] | None = None
773        if raw_vendors := payload.get("vendors"):
774            vendors = tuple(
775                milestones.MilestoneVendor(
776                    vendor_hash=vendor["vendorHash"],
777                    preview_itemhash=vendor.get("previewItemHash"),
778                )
779                for vendor in raw_vendors
780            )
781
782        return milestones.Milestone(
783            hash=payload["milestoneHash"],
784            start_date=start_date,
785            end_date=end_date,
786            order=payload["order"],
787            rewards=rewards,
788            available_quests=quests,
789            activities=activities,
790            vendors=vendors,
791        )
def deserialize_characters( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
808    def deserialize_characters(
809        self, payload: typedefs.JSONObject
810    ) -> collections.Mapping[int, character.Character]:
811        return {
812            int(char_id): self._set_character_attrs(char)
813            for char_id, char in payload["data"].items()
814        }
def deserialize_character( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.Character:
816    def deserialize_character(
817        self, payload: typedefs.JSONObject
818    ) -> character.Character:
819        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
821    def deserialize_character_equipments(
822        self, payload: typedefs.JSONObject
823    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
824        return {
825            int(char_id): self.deserialize_profile_items(item)
826            for char_id, item in payload["data"].items()
827        }
def deserialize_character_activities( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
829    def deserialize_character_activities(
830        self, payload: typedefs.JSONObject
831    ) -> collections.Mapping[int, activity.CharacterActivity]:
832        return {
833            int(char_id): self.deserialize_character_activity(data)
834            for char_id, data in payload["data"].items()
835        }
def deserialize_characters_render_data( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
837    def deserialize_characters_render_data(
838        self, payload: typedefs.JSONObject
839    ) -> collections.Mapping[int, character.RenderedData]:
840        return {
841            int(char_id): self.deserialize_character_render_data(data)
842            for char_id, data in payload["data"].items()
843        }
def deserialize_character_progressions( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
845    def deserialize_character_progressions(
846        self, payload: typedefs.JSONObject
847    ) -> character.CharacterProgression:
848        progressions_ = {
849            int(prog_id): self.deserialize_progressions(prog)
850            for prog_id, prog in payload["progressions"].items()
851        }
852
853        factions = {
854            int(faction_id): self._deserialize_factions(faction)
855            for faction_id, faction in payload["factions"].items()
856        }
857
858        milestones_ = {
859            int(milestone_hash): self.deserialize_milestone(milestone)
860            for milestone_hash, milestone in payload["milestones"].items()
861        }
862
863        uninstanced_item_objectives = {
864            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
865            for item_hash, obj in payload["uninstancedItemObjectives"].items()
866        }
867
868        artifact = payload["seasonalArtifact"]
869        seasonal_artifact = season.CharacterScopedArtifact(
870            hash=artifact["artifactHash"],
871            points_used=artifact["pointsUsed"],
872            reset_count=artifact["resetCount"],
873            tiers=tuple(
874                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
875            ),
876        )
877        checklists = payload["checklists"]
878
879        return character.CharacterProgression(
880            progressions=progressions_,
881            factions=factions,
882            checklists=checklists,
883            milestones=milestones_,
884            seasonal_artifact=seasonal_artifact,
885            uninstanced_item_objectives=uninstanced_item_objectives,
886        )
def deserialize_character_progressions_mapping( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
889    def deserialize_character_progressions_mapping(self, payload: typedefs.JSONObject) -> collections.Mapping[int, character.CharacterProgression]:
890        character_progressions: collections.MutableMapping[int, character.CharacterProgression] = {}
891        for char_id, data in payload["data"].items():
892            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)
893        return character_progressions
def deserialize_characters_records( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
896    def deserialize_characters_records(
897        self,
898        payload: typedefs.JSONObject,
899    ) -> collections.Mapping[int, records.CharacterRecord]:
900        return {
901            int(rec_id): self.deserialize_character_records(
902                rec, record_hashes=payload.get("featuredRecordHashes", ())
903            )
904            for rec_id, rec in payload["records"].items()
905        }
def deserialize_profile_records( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
907    def deserialize_profile_records(
908        self, payload: typedefs.JSONObject
909    ) -> collections.Mapping[int, records.Record]:
910        raw_profile_records = payload["data"]
911        scores = records.RecordScores(
912            current_score=raw_profile_records["score"],
913            legacy_score=raw_profile_records["legacyScore"],
914            lifetime_score=raw_profile_records["lifetimeScore"],
915        )
916        return {
917            int(record_id): self.deserialize_records(
918                record,
919                scores,
920                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
921                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
922            )
923            for record_id, record in raw_profile_records["records"].items()
924        }
def deserialize_craftables_component( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
960    def deserialize_craftables_component(
961        self, payload: typedefs.JSONObject
962    ) -> components.CraftablesComponent:
963        return components.CraftablesComponent(
964            net=self._net,
965            craftables={
966                int(item_id): self._deserialize_craftable_item(item)
967                for item_id, item in payload["craftables"].items()
968                if item is not None
969            },
970            crafting_root_node_hash=payload["craftingRootNodeHash"],
971        )
def deserialize_components( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.Component:
 973    def deserialize_components(  # noqa: C901 Too complex.
 974        self, payload: typedefs.JSONObject
 975    ) -> components.Component:
 976        # Due to how complex this method is, We'll stick to
 977        # typing.Optional here.
 978
 979        profile_: profile.Profile | None = None
 980        if raw_profile := payload.get("profile"):
 981            profile_ = self.deserialize_profile(raw_profile)
 982
 983        profile_progression: profile.ProfileProgression | None = None
 984        if raw_profile_progression := payload.get("profileProgression"):
 985            profile_progression = self.deserialize_profile_progression(
 986                raw_profile_progression
 987            )
 988
 989        profile_currencies: typing.Optional[
 990            collections.Sequence[profile.ProfileItemImpl]
 991        ] = None
 992        if raw_profile_currencies := payload.get("profileCurrencies"):
 993            if "data" in raw_profile_currencies:
 994                profile_currencies = self.deserialize_profile_items(
 995                    raw_profile_currencies["data"]
 996                )
 997
 998        profile_inventories: typing.Optional[
 999            collections.Sequence[profile.ProfileItemImpl]
1000        ] = None
1001        if raw_profile_inventories := payload.get("profileInventory"):
1002            if "data" in raw_profile_inventories:
1003                profile_inventories = self.deserialize_profile_items(
1004                    raw_profile_inventories["data"]
1005                )
1006
1007        profile_records: typing.Optional[
1008            collections.Mapping[int, records.Record]
1009        ] = None
1010
1011        if raw_profile_records_ := payload.get("profileRecords"):
1012            profile_records = self.deserialize_profile_records(raw_profile_records_)
1013
1014        characters: typing.Optional[
1015            collections.Mapping[int, character.Character]
1016        ] = None
1017        if raw_characters := payload.get("characters"):
1018            characters = self.deserialize_characters(raw_characters)
1019
1020        character_records: typing.Optional[
1021            collections.Mapping[int, records.CharacterRecord]
1022        ] = None
1023
1024        if raw_character_records := payload.get("characterRecords"):
1025            # Had to do it in two steps..
1026            to_update = {}
1027            for _, data in raw_character_records["data"].items():
1028                for record_id, record in data.items():
1029                    to_update[record_id] = record
1030
1031            character_records = {
1032                int(rec_id): self.deserialize_character_records(
1033                    rec, record_hashes=to_update.get("featuredRecordHashes", ())
1034                )
1035                for rec_id, rec in to_update["records"].items()
1036            }
1037
1038        character_equipments: typing.Optional[
1039            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1040        ] = None
1041        if raw_character_equips := payload.get("characterEquipment"):
1042            character_equipments = self.deserialize_character_equipments(
1043                raw_character_equips
1044            )
1045
1046        character_inventories: typing.Optional[
1047            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1048        ] = None
1049        if raw_character_inventories := payload.get("characterInventories"):
1050            if "data" in raw_character_inventories:
1051                character_inventories = self.deserialize_character_equipments(
1052                    raw_character_inventories
1053                )
1054
1055        character_activities: typing.Optional[
1056            collections.Mapping[int, activity.CharacterActivity]
1057        ] = None
1058        if raw_char_acts := payload.get("characterActivities"):
1059            character_activities = self.deserialize_character_activities(raw_char_acts)
1060
1061        character_render_data: typing.Optional[
1062            collections.Mapping[int, character.RenderedData]
1063        ] = None
1064        if raw_character_render_data := payload.get("characterRenderData"):
1065            character_render_data = self.deserialize_characters_render_data(
1066                raw_character_render_data
1067            )
1068
1069        character_progressions: typing.Optional[
1070            collections.Mapping[int, character.CharacterProgression]
1071        ] = None
1072
1073        if raw_character_progressions := payload.get("characterProgressions"):
1074            character_progressions = self.deserialize_character_progressions_mapping(
1075                raw_character_progressions
1076            )
1077
1078        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1079        if raw_profile_string_vars := payload.get("profileStringVariables"):
1080            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1081
1082        character_string_vars: typing.Optional[
1083            collections.Mapping[int, collections.Mapping[int, int]]
1084        ] = None
1085        if raw_character_string_vars := payload.get("characterStringVariables"):
1086            character_string_vars = {
1087                int(char_id): data["integerValuesByHash"]
1088                for char_id, data in raw_character_string_vars["data"].items()
1089            }
1090
1091        metrics: typing.Optional[
1092            collections.Sequence[
1093                collections.Mapping[int, tuple[bool, records.Objective | None]]
1094            ]
1095        ] = None
1096        root_node_hash: int | None = None
1097
1098        if raw_metrics := payload.get("metrics"):
1099            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1100            metrics = tuple(
1101                {
1102                    int(metrics_hash): (
1103                        data["invisible"],
1104                        self.deserialize_objectives(data["objectiveProgress"])
1105                        if "objectiveProgress" in data
1106                        else None,
1107                    )
1108                }
1109                for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1110            )
1111        transitory: fireteams.FireteamParty | None = None
1112        if raw_transitory := payload.get("profileTransitoryData"):
1113            if "data" in raw_transitory:
1114                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1115
1116        item_components: components.ItemsComponent | None = None
1117        if raw_item_components := payload.get("itemComponents"):
1118            item_components = self.deserialize_items_component(raw_item_components)
1119
1120        profile_plugsets: typing.Optional[
1121            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1122        ] = None
1123
1124        if raw_profile_plugs := payload.get("profilePlugSets"):
1125            profile_plugsets = {
1126                int(index): [self.deserialize_plug_item_state(state) for state in data]
1127                for index, data in raw_profile_plugs["data"]["plugs"].items()
1128            }
1129
1130        character_plugsets: typing.Optional[
1131            collections.Mapping[
1132                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1133            ]
1134        ] = None
1135        if raw_char_plugsets := payload.get("characterPlugSets"):
1136            character_plugsets = {
1137                int(char_id): {
1138                    int(index): [
1139                        self.deserialize_plug_item_state(state) for state in data
1140                    ]
1141                    for index, data in inner["plugs"].items()
1142                }
1143                for char_id, inner in raw_char_plugsets["data"].items()
1144            }
1145
1146        character_collectibles: typing.Optional[
1147            collections.Mapping[int, items.Collectible]
1148        ] = None
1149        if raw_character_collectibles := payload.get("characterCollectibles"):
1150            character_collectibles = {
1151                int(char_id): self._deserialize_collectible(data)
1152                for char_id, data in raw_character_collectibles["data"].items()
1153            }
1154
1155        profile_collectibles: items.Collectible | None = None
1156        if raw_profile_collectibles := payload.get("profileCollectibles"):
1157            profile_collectibles = self._deserialize_collectible(
1158                raw_profile_collectibles["data"]
1159            )
1160
1161        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1162        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1163            profile_nodes = {
1164                int(node_hash): self._deserialize_node(node)
1165                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1166            }
1167
1168        character_nodes: typing.Optional[
1169            collections.Mapping[int, collections.Mapping[int, records.Node]]
1170        ] = None
1171        if raw_character_nodes := payload.get("characterPresentationNodes"):
1172            character_nodes = {
1173                int(char_id): {
1174                    int(node_hash): self._deserialize_node(node)
1175                    for node_hash, node in each_character["nodes"].items()
1176                }
1177                for char_id, each_character in raw_character_nodes["data"].items()
1178            }
1179
1180        platform_silver: typing.Optional[
1181            collections.Mapping[str, profile.ProfileItemImpl]
1182        ] = None
1183        if raw_platform_silver := payload.get("platformSilver"):
1184            if "data" in raw_platform_silver:
1185                platform_silver = {
1186                    platform_name: self.deserialize_profile_item(item)
1187                    for platform_name, item in raw_platform_silver["data"][
1188                        "platformSilver"
1189                    ].items()
1190                }
1191
1192        character_currency_lookups: typing.Optional[
1193            collections.Mapping[int, collections.Sequence[items.Currency]]
1194        ] = None
1195        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1196            if "data" in raw_char_lookups:
1197                character_currency_lookups = {
1198                    int(char_id): self._deserialize_currencies(currency)
1199                    for char_id, currency in raw_char_lookups["data"].items()
1200                }
1201
1202        character_craftables: typing.Optional[
1203            collections.Mapping[int, components.CraftablesComponent]
1204        ] = None
1205        if raw_character_craftables := payload.get("characterCraftables"):
1206            if "data" in raw_character_craftables:
1207                character_craftables = {
1208                    int(char_id): self.deserialize_craftables_component(craftable)
1209                    for char_id, craftable in raw_character_craftables["data"].items()
1210                }
1211
1212        return components.Component(
1213            profiles=profile_,
1214            profile_progression=profile_progression,
1215            profile_currencies=profile_currencies,
1216            profile_inventories=profile_inventories,
1217            profile_records=profile_records,
1218            characters=characters,
1219            character_records=character_records,
1220            character_equipments=character_equipments,
1221            character_inventories=character_inventories,
1222            character_activities=character_activities,
1223            character_render_data=character_render_data,
1224            character_progressions=character_progressions,
1225            profile_string_variables=profile_string_vars,
1226            character_string_variables=character_string_vars,
1227            metrics=metrics,
1228            root_node_hash=root_node_hash,
1229            transitory=transitory,
1230            item_components=item_components,
1231            profile_plugsets=profile_plugsets,
1232            character_plugsets=character_plugsets,
1233            character_collectibles=character_collectibles,
1234            profile_collectibles=profile_collectibles,
1235            profile_nodes=profile_nodes,
1236            character_nodes=character_nodes,
1237            platform_silver=platform_silver,
1238            character_currency_lookups=character_currency_lookups,
1239            character_craftables=character_craftables,
1240        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1242    def deserialize_items_component(
1243        self, payload: typedefs.JSONObject
1244    ) -> components.ItemsComponent:
1245        # Due to how complex this method is, We'll stick to typing.Optional.
1246        instances: typing.Optional[
1247            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1248        ] = None
1249        if raw_instances := payload.get("instances"):
1250            instances = tuple(
1251                {int(ins_id): self.deserialize_instanced_item(item)}
1252                for ins_id, item in raw_instances["data"].items()
1253            )
1254
1255        render_data: typing.Optional[
1256            collections.Mapping[int, tuple[bool, dict[int, int]]]
1257        ] = None
1258        if raw_render_data := payload.get("renderData"):
1259            render_data = {
1260                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1261                for ins_id, data in raw_render_data["data"].items()
1262            }
1263
1264        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1265        if raw_stats := payload.get("stats"):
1266            stats = {}
1267            for ins_id, stat in raw_stats["data"].items():
1268                for _, items_ in stat.items():
1269                    stats[int(ins_id)] = self.deserialize_item_stats_view(items_)
1270
1271        sockets: typing.Optional[
1272            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1273        ] = None
1274        if raw_sockets := payload.get("sockets"):
1275            sockets = {
1276                int(ins_id): tuple(
1277                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1278                )
1279                for ins_id, item in raw_sockets["data"].items()
1280            }
1281
1282        objectives: typing.Optional[
1283            collections.Mapping[int, collections.Sequence[records.Objective]]
1284        ] = None
1285        if raw_objectives := payload.get("objectives"):
1286            objectives = {
1287                int(ins_id): tuple(
1288                    self.deserialize_objectives(objective)
1289                    for objective in data["objectives"]
1290                )
1291                for ins_id, data in raw_objectives["data"].items()
1292            }
1293
1294        perks: typing.Optional[
1295            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1296        ] = None
1297        if raw_perks := payload.get("perks"):
1298            perks = {
1299                int(ins_id): tuple(
1300                    self.deserialize_item_perk(perk) for perk in item["perks"]
1301                )
1302                for ins_id, item in raw_perks["data"].items()
1303            }
1304
1305        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1306        if raw_plug_states := payload.get("plugStates"):
1307            plug_states = tuple(
1308                self.deserialize_plug_item_state(plug)
1309                for _, plug in raw_plug_states["data"].items()
1310            )
1311
1312        reusable_plugs: typing.Optional[
1313            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1314        ] = None
1315        if raw_re_plugs := payload.get("reusablePlugs"):
1316            reusable_plugs = {
1317                int(ins_id): tuple(
1318                    self.deserialize_plug_item_state(state) for state in inner
1319                )
1320                for ins_id, plug in raw_re_plugs["data"].items()
1321                for inner in tuple(plug["plugs"].values())
1322            }
1323
1324        plug_objectives: typing.Optional[
1325            collections.Mapping[
1326                int, collections.Mapping[int, collections.Collection[records.Objective]]
1327            ]
1328        ] = None
1329        if raw_plug_objectives := payload.get("plugObjectives"):
1330            plug_objectives = {
1331                int(ins_id): {
1332                    int(obj_hash): tuple(
1333                        self.deserialize_objectives(obj) for obj in objs
1334                    )
1335                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1336                }
1337                for ins_id, inner in raw_plug_objectives["data"].items()
1338            }
1339
1340        return components.ItemsComponent(
1341            sockets=sockets,
1342            stats=stats,
1343            render_data=render_data,
1344            instances=instances,
1345            objectives=objectives,
1346            perks=perks,
1347            plug_states=plug_states,
1348            reusable_plugs=reusable_plugs,
1349            plug_objectives=plug_objectives,
1350        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1352    def deserialize_character_component(
1353        self, payload: typedefs.JSONObject
1354    ) -> components.CharacterComponent:
1355        character_: character.Character | None = None
1356        if raw_singular_character := payload.get("character"):
1357            character_ = self.deserialize_character(raw_singular_character["data"])
1358
1359        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1360        if raw_inventory := payload.get("inventory"):
1361            if "data" in raw_inventory:
1362                inventory = self.deserialize_profile_items(raw_inventory["data"])
1363
1364        activities: activity.CharacterActivity | None = None
1365        if raw_activities := payload.get("activities"):
1366            activities = self.deserialize_character_activity(raw_activities["data"])
1367
1368        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1369        if raw_equipments := payload.get("equipment"):
1370            equipment = self.deserialize_profile_items(raw_equipments["data"])
1371
1372        progressions_: character.CharacterProgression | None = None
1373        if raw_progressions := payload.get("progressions"):
1374            progressions_ = self.deserialize_character_progressions(
1375                raw_progressions["data"]
1376            )
1377
1378        render_data: character.RenderedData | None = None
1379        if raw_render_data := payload.get("renderData"):
1380            render_data = self.deserialize_character_render_data(
1381                raw_render_data["data"]
1382            )
1383
1384        character_records: typing.Optional[
1385            collections.Mapping[int, records.CharacterRecord]
1386        ] = None
1387        if raw_char_records := payload.get("records"):
1388            character_records = self.deserialize_characters_records(
1389                raw_char_records["data"]
1390            )
1391
1392        item_components: components.ItemsComponent | None = None
1393        if raw_item_components := payload.get("itemComponents"):
1394            item_components = self.deserialize_items_component(raw_item_components)
1395
1396        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1397        if raw_nodes := payload.get("presentationNodes"):
1398            nodes = {
1399                int(node_hash): self._deserialize_node(node)
1400                for node_hash, node in raw_nodes["data"]["nodes"].items()
1401            }
1402
1403        collectibles: items.Collectible | None = None
1404        if raw_collectibles := payload.get("collectibles"):
1405            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1406
1407        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1408        if raw_currencies := payload.get("currencyLookups"):
1409            if "data" in raw_currencies:
1410                currency_lookups = self._deserialize_currencies(raw_currencies)
1411
1412        return components.CharacterComponent(
1413            activities=activities,
1414            equipment=equipment,
1415            inventory=inventory,
1416            progressions=progressions_,
1417            render_data=render_data,
1418            character=character_,
1419            character_records=character_records,
1420            profile_records=None,
1421            item_components=item_components,
1422            currency_lookups=currency_lookups,
1423            collectibles=collectibles,
1424            nodes=nodes,
1425        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: collections.abc.Mapping[str, typing.Any]) -> Iterator[aiobungie.crates.entity.SearchableEntity]:
1444    def deserialize_inventory_results(
1445        self, payload: typedefs.JSONObject
1446    ) -> iterators.Iterator[entity.SearchableEntity]:
1447        return iterators.Iterator(
1448            [
1449                entity.SearchableEntity(
1450                    net=self._net,
1451                    hash=data["hash"],
1452                    entity_type=data["entityType"],
1453                    weight=data["weight"],
1454                    suggested_words=payload["suggestedWords"],
1455                    name=data["displayProperties"]["name"],
1456                    has_icon=data["displayProperties"]["hasIcon"],
1457                    description=typedefs.unknown(
1458                        data["displayProperties"]["description"]
1459                    ),
1460                    icon=assets.Image(path=data["displayProperties"]["icon"]),
1461                )
1462                for data in payload["results"]["results"]
1463            ]
1464        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1493    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1494        self, payload: typedefs.JSONObject, /
1495    ) -> entity.InventoryEntity:
1496        props = self._set_entity_attrs(payload)
1497        objects = self._deserialize_inventory_item_objects(payload)
1498
1499        collectible_hash: int | None = None
1500        if raw_collectible_hash := payload.get("collectibleHash"):
1501            collectible_hash = int(raw_collectible_hash)
1502
1503        secondary_icon: assets.Image | None = None
1504        if raw_second_icon := payload.get("secondaryIcon"):
1505            secondary_icon = assets.Image(path=raw_second_icon)
1506
1507        secondary_overlay: assets.Image | None = None
1508        if raw_second_overlay := payload.get("secondaryOverlay"):
1509            secondary_overlay = assets.Image(path=raw_second_overlay)
1510
1511        secondary_special: assets.Image | None = None
1512        if raw_second_special := payload.get("secondarySpecial"):
1513            secondary_special = assets.Image(path=raw_second_special)
1514
1515        screenshot: assets.Image | None = None
1516        if raw_screenshot := payload.get("screenshot"):
1517            screenshot = assets.Image(path=raw_screenshot)
1518
1519        watermark_icon: assets.Image | None = None
1520        if raw_watermark_icon := payload.get("iconWatermark"):
1521            watermark_icon = assets.Image(path=raw_watermark_icon)
1522
1523        watermark_shelved: assets.Image | None = None
1524        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1525            watermark_shelved = assets.Image(path=raw_watermark_shelved)
1526
1527        about: str | None = None
1528        if raw_about := payload.get("flavorText"):
1529            about = raw_about
1530
1531        ui_item_style: str | None = None
1532        if raw_ui_style := payload.get("uiItemDisplayStyle"):
1533            ui_item_style = raw_ui_style
1534
1535        tier_and_name: str | None = None
1536        if raw_tier_and_name := payload.get("itemTypeAndTierDisplayName"):
1537            tier_and_name = raw_tier_and_name
1538
1539        type_name: str | None = None
1540        if raw_type_name := payload.get("itemTypeDisplayName"):
1541            type_name = raw_type_name
1542
1543        display_source: str | None = None
1544        if raw_display_source := payload.get("displaySource"):
1545            display_source = raw_display_source
1546
1547        lorehash: int | None = None
1548        if raw_lore_hash := payload.get("loreHash"):
1549            lorehash = int(raw_lore_hash)
1550
1551        summary_hash: int | None = None
1552        if raw_summary_hash := payload.get("summaryItemHash"):
1553            summary_hash = raw_summary_hash
1554
1555        breaker_type_hash: int | None = None
1556        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1557            breaker_type_hash = int(raw_breaker_type_hash)
1558
1559        damage_types: typing.Optional[collections.Sequence[int]] = None
1560        if raw_damage_types := payload.get("damageTypes"):
1561            damage_types = tuple(int(type_) for type_ in raw_damage_types)
1562
1563        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1564        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1565            damagetype_hashes = tuple(int(type_) for type_ in raw_damagetype_hashes)
1566
1567        default_damagetype_hash: int | None = None
1568        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1569            default_damagetype_hash = int(raw_defaultdmg_hash)
1570
1571        emblem_objective_hash: int | None = None
1572        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1573            emblem_objective_hash = int(raw_emblem_obj_hash)
1574
1575        tier_type: enums.TierType | None = None
1576        tier: enums.ItemTier | None = None
1577        bucket_hash: int | None = None
1578        recovery_hash: int | None = None
1579        tier_name: str | None = None
1580        isinstance_item: bool = False
1581        expire_tool_tip: str | None = None
1582        expire_in_orbit_message: str | None = None
1583        suppress_expiration: bool = False
1584        max_stack_size: int | None = None
1585        stack_label: str | None = None
1586
1587        if inventory := payload.get("inventory"):
1588            tier_type = enums.TierType(int(inventory["tierType"]))
1589            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1590            bucket_hash = int(inventory["bucketTypeHash"])
1591            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1592            tier_name = inventory["tierTypeName"]
1593            isinstance_item = inventory["isInstanceItem"]
1594            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1595            max_stack_size = int(inventory["maxStackSize"])
1596
1597            try:
1598                stack_label = inventory["stackUniqueLabel"]
1599            except KeyError:
1600                pass
1601
1602        if "traitHashes" in payload:
1603            trait_hashes = tuple(
1604                int(trait_hash) for trait_hash in payload["traitHashes"]
1605            )
1606        else:
1607            trait_hashes = ()
1608
1609        if "traitIds" in payload:
1610            trait_ids = tuple(trait_id for trait_id in payload["traitIds"])
1611        else:
1612            trait_ids = ()
1613
1614        return entity.InventoryEntity(
1615            net=self._net,
1616            collectible_hash=collectible_hash,
1617            name=props.name,
1618            about=about,
1619            emblem_objective_hash=emblem_objective_hash,
1620            suppress_expiration=suppress_expiration,
1621            max_stack_size=max_stack_size,
1622            stack_label=stack_label,
1623            tier=tier,
1624            tier_type=tier_type,
1625            tier_name=tier_name,
1626            bucket_hash=bucket_hash,
1627            recovery_bucket_hash=recovery_hash,
1628            isinstance_item=isinstance_item,
1629            expire_in_orbit_message=expire_in_orbit_message,
1630            expiration_tooltip=expire_tool_tip,
1631            lore_hash=lorehash,
1632            type_and_tier_name=tier_and_name,
1633            summary_hash=summary_hash,
1634            ui_display_style=ui_item_style,
1635            type_name=type_name,
1636            breaker_type_hash=breaker_type_hash,
1637            description=props.description,
1638            display_source=display_source,
1639            hash=props.hash,
1640            damage_types=damage_types,
1641            index=props.index,
1642            icon=props.icon,
1643            has_icon=props.has_icon,
1644            screenshot=screenshot,
1645            watermark_icon=watermark_icon,
1646            watermark_shelved=watermark_shelved,
1647            secondary_icon=secondary_icon,
1648            secondary_overlay=secondary_overlay,
1649            secondary_special=secondary_special,
1650            type=enums.ItemType(int(payload["itemType"])),
1651            category_hashes=tuple(
1652                int(hash_) for hash_ in payload["itemCategoryHashes"]
1653            ),
1654            item_class=enums.Class(int(payload["classType"])),
1655            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1656            breaker_type=int(payload["breakerType"]),
1657            default_damagetype=int(payload["defaultDamageType"]),
1658            default_damagetype_hash=default_damagetype_hash,
1659            damagetype_hashes=damagetype_hashes,
1660            tooltip_notifications=payload["tooltipNotifications"],
1661            not_transferable=payload["nonTransferrable"],
1662            allow_actions=payload["allowActions"],
1663            is_equippable=payload["equippable"],
1664            objects=objects,
1665            background_colors=payload.get("backgroundColor", {}),
1666            season_hash=payload.get("seasonHash"),
1667            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1668            trait_hashes=trait_hashes,
1669            trait_ids=trait_ids,
1670        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1672    def deserialize_objective_entity(
1673        self, payload: typedefs.JSONObject, /
1674    ) -> entity.ObjectiveEntity:
1675        props = self._set_entity_attrs(payload)
1676        return entity.ObjectiveEntity(
1677            net=self._net,
1678            hash=props.hash,
1679            index=props.index,
1680            description=props.description,
1681            name=props.name,
1682            has_icon=props.has_icon,
1683            icon=props.icon,
1684            unlock_value_hash=payload["unlockValueHash"],
1685            completion_value=payload["completionValue"],
1686            scope=entity.GatingScope(int(payload["scope"])),
1687            location_hash=payload["locationHash"],
1688            allowed_negative_value=payload["allowNegativeValue"],
1689            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1690            counting_downward=payload["isCountingDownward"],
1691            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1692            progress_description=payload["progressDescription"],
1693            perks=payload["perks"],
1694            stats=payload["stats"],
1695            minimum_visibility=payload["minimumVisibilityThreshold"],
1696            allow_over_completion=payload["allowOvercompletion"],
1697            show_value_style=payload["showValueOnComplete"],
1698            display_only_objective=payload["isDisplayOnlyObjective"],
1699            complete_value_style=entity.ValueUIStyle(
1700                int(payload["completedValueStyle"])
1701            ),
1702            progress_value_style=entity.ValueUIStyle(
1703                int(payload["inProgressValueStyle"])
1704            ),
1705            ui_label=payload["uiLabel"],
1706            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1707        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1735    def deserialize_activity(
1736        self,
1737        payload: typedefs.JSONObject,
1738        /,
1739    ) -> activity.Activity:
1740        period = time.clean_date(payload["period"])
1741        details = payload["activityDetails"]
1742        ref_id = int(details["referenceId"])
1743        instance_id = int(details["instanceId"])
1744        mode = enums.GameMode(details["mode"])
1745        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1746        is_private = details["isPrivate"]
1747        membership_type = enums.MembershipType(int(details["membershipType"]))
1748
1749        # Since we're using the same fields for post activity method
1750        # this check is required since post activity doesn't values values
1751        values = self._deserialize_activity_values(payload["values"])
1752
1753        return activity.Activity(
1754            net=self._net,
1755            hash=ref_id,
1756            instance_id=instance_id,
1757            mode=mode,
1758            modes=modes,
1759            is_private=is_private,
1760            membership_type=membership_type,
1761            occurred_at=period,
1762            values=values,
1763        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: collections.abc.Mapping[str, typing.Any]) -> Iterator[aiobungie.crates.activity.Activity]:
1765    def deserialize_activities(
1766        self, payload: typedefs.JSONObject
1767    ) -> iterators.Iterator[activity.Activity]:
1768        return iterators.Iterator(
1769            [
1770                self.deserialize_activity(activity_)
1771                for activity_ in payload["activities"]
1772            ]
1773        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
def deserialize_extended_weapon_values( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1775    def deserialize_extended_weapon_values(
1776        self, payload: typedefs.JSONObject
1777    ) -> activity.ExtendedWeaponValues:
1778        assists: int | None = None
1779        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1780            assists = raw_assists["basic"]["value"]
1781        assists_damage: int | None = None
1782
1783        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1784            assists_damage = raw_assists_damage["basic"]["value"]
1785
1786        return activity.ExtendedWeaponValues(
1787            reference_id=int(payload["referenceId"]),
1788            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1789            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1790                "value"
1791            ],
1792            assists=assists,
1793            assists_damage=assists_damage,
1794            precision_kills_percentage=(
1795                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1796                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1797                    "displayValue"
1798                ],
1799            ),
1800        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1821    def deserialize_post_activity_player(
1822        self, payload: typedefs.JSONObject, /
1823    ) -> activity.PostActivityPlayer:
1824        player = payload["player"]
1825
1826        class_hash: int | None = None
1827        if (class_hash := player.get("classHash")) is not None:
1828            class_hash = class_hash
1829
1830        race_hash: int | None = None
1831        if (race_hash := player.get("raceHash")) is not None:
1832            race_hash = race_hash
1833
1834        gender_hash: int | None = None
1835        if (gender_hash := player.get("genderHash")) is not None:
1836            gender_hash = gender_hash
1837
1838        character_class: str | None = None
1839        if character_class := player.get("characterClass"):
1840            character_class = character_class
1841
1842        character_level: int | None = None
1843        if (character_level := player.get("characterLevel")) is not None:
1844            character_level = character_level
1845
1846        return activity.PostActivityPlayer(
1847            standing=int(payload["standing"]),
1848            score=int(payload["score"]["basic"]["value"]),
1849            character_id=payload["characterId"],
1850            destiny_user=self.deserialize_destiny_membership(player["destinyUserInfo"]),
1851            character_class=character_class,
1852            character_level=character_level,
1853            race_hash=race_hash,
1854            gender_hash=gender_hash,
1855            class_hash=class_hash,
1856            light_level=int(player["lightLevel"]),
1857            emblem_hash=int(player["emblemHash"]),
1858            values=self._deserialize_activity_values(payload["values"]),
1859            extended_values=self._deserialize_extended_values(payload["extended"]),
1860        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1872    def deserialize_post_activity(
1873        self, payload: typedefs.JSONObject
1874    ) -> activity.PostActivity:
1875        period = time.clean_date(payload["period"])
1876        details = payload["activityDetails"]
1877        ref_id = int(details["referenceId"])
1878        instance_id = int(details["instanceId"])
1879        mode = enums.GameMode(details["mode"])
1880        modes = tuple(enums.GameMode(int(mode_)) for mode_ in details["modes"])
1881        is_private = details["isPrivate"]
1882        membership_type = enums.MembershipType(int(details["membershipType"]))
1883        return activity.PostActivity(
1884            net=self._net,
1885            hash=ref_id,
1886            membership_type=membership_type,
1887            instance_id=instance_id,
1888            mode=mode,
1889            modes=modes,
1890            is_private=is_private,
1891            occurred_at=period,
1892            starting_phase=int(payload["startingPhaseIndex"]),
1893            players=tuple(
1894                self.deserialize_post_activity_player(player)
1895                for player in payload["entries"]
1896            ),
1897            teams=tuple(
1898                self._deserialize_post_activity_team(team) for team in payload["teams"]
1899            ),
1900        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1938    def deserialize_aggregated_activity(
1939        self, payload: typedefs.JSONObject
1940    ) -> activity.AggregatedActivity:
1941        return activity.AggregatedActivity(
1942            hash=int(payload["activityHash"]),
1943            values=self._deserialize_aggregated_activity_values(payload["values"]),
1944        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: collections.abc.Mapping[str, typing.Any]) -> Iterator[aiobungie.crates.activity.AggregatedActivity]:
1946    def deserialize_aggregated_activities(
1947        self, payload: typedefs.JSONObject
1948    ) -> iterators.Iterator[activity.AggregatedActivity]:
1949        return iterators.Iterator(
1950            [
1951                self.deserialize_aggregated_activity(activity)
1952                for activity in payload["activities"]
1953            ]
1954        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
1956    def deserialize_linked_profiles(
1957        self, payload: typedefs.JSONObject
1958    ) -> profile.LinkedProfile:
1959        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
1960
1961        if raw_profile := payload.get("profiles"):
1962            profiles = tuple(
1963                self.deserialize_destiny_membership(p) for p in raw_profile
1964            )
1965        else:
1966            profiles = ()
1967
1968        error_profiles = ()
1969        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
1970            for raw_error_p in raw_profiles_with_errors:
1971                if "infoCard" in raw_error_p:
1972                    error_profiles = tuple(
1973                        self.deserialize_destiny_membership(error_p)
1974                        for error_p in raw_error_p
1975                    )
1976
1977        return profile.LinkedProfile(
1978            bungie_user=bungie_user,
1979            profiles=profiles,
1980            profiles_with_errors=error_profiles,
1981        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
1983    def deserialize_clan_banners(
1984        self, payload: typedefs.JSONObject
1985    ) -> collections.Sequence[clans.ClanBanner]:
1986        if banners := payload.get("clanBannerDecals"):
1987            banner_obj = tuple(
1988                clans.ClanBanner(
1989                    id=int(k),
1990                    foreground=assets.Image(path=v["foregroundPath"]),
1991                    background=assets.Image(path=v["backgroundPath"]),
1992                )
1993                for k, v in banners.items()
1994            )
1995        else:
1996            banner_obj = ()
1997        return banner_obj

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
1999    def deserialize_public_milestone_content(
2000        self, payload: typedefs.JSONObject
2001    ) -> milestones.MilestoneContent:
2002        if raw_categories := payload.get("itemCategories"):
2003            items_categories = tuple(
2004                milestones.MilestoneItems(
2005                    title=item["title"], hashes=item["itemHashes"]
2006                )
2007                for item in raw_categories
2008            )
2009        else:
2010            items_categories = ()
2011
2012        return milestones.MilestoneContent(
2013            about=typedefs.unknown(payload["about"]),
2014            status=typedefs.unknown(payload["status"]),
2015            tips=payload.get("tips", ()),
2016            items=items_categories,
2017        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: collections.abc.Mapping[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2019    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2020        bungie_user: user.BungieUser | None = None
2021
2022        if raw_bungie_user := payload.get("bungieNetUser"):
2023            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2024
2025        return friends.Friend(
2026            net=self._net,
2027            id=int(payload["lastSeenAsMembershipId"]),
2028            name=typedefs.unknown(payload["bungieGlobalDisplayName"]),
2029            code=payload.get("bungieGlobalDisplayNameCode"),
2030            relationship=enums.Relationship(payload["relationship"]),
2031            user=bungie_user,
2032            online_status=enums.Presence(payload["onlineStatus"]),
2033            online_title=payload["onlineTitle"],
2034            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2035        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2037    def deserialize_friends(
2038        self, payload: typedefs.JSONObject
2039    ) -> collections.Sequence[friends.Friend]:
2040        return tuple(self.deserialize_friend(friend) for friend in payload["friends"])

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2042    def deserialize_friend_requests(
2043        self, payload: typedefs.JSONObject
2044    ) -> friends.FriendRequestView:
2045        if raw_incoming_requests := payload.get("incomingRequests"):
2046            incoming = tuple(
2047                self.deserialize_friend(incoming_request)
2048                for incoming_request in raw_incoming_requests
2049            )
2050        else:
2051            incoming = ()
2052
2053        if raw_outgoing_requests := payload.get("outgoingRequests"):
2054            outgoing = tuple(
2055                self.deserialize_friend(outgoing_request)
2056                for outgoing_request in raw_outgoing_requests
2057            )
2058        else:
2059            outgoing = ()
2060
2061        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]:
2092    def deserialize_fireteams(
2093        self, payload: typedefs.JSONObject
2094    ) -> collections.Sequence[fireteams.Fireteam]:
2095        if "results" in payload:
2096            fireteams_ = tuple(
2097                self._set_fireteam_fields(
2098                    elem, total_results=int(payload["totalResults"])
2099                )
2100                for elem in payload["results"]
2101            )
2102        else:
2103            fireteams_ = ()
2104        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2106    def deserialize_fireteam_destiny_users(
2107        self, payload: typedefs.JSONObject
2108    ) -> fireteams.FireteamUser:
2109        destiny_obj = self.deserialize_destiny_membership(payload)
2110        return fireteams.FireteamUser(
2111            net=self._net,
2112            id=destiny_obj.id,
2113            code=destiny_obj.code,
2114            icon=destiny_obj.icon,
2115            types=destiny_obj.types,
2116            type=destiny_obj.type,
2117            is_public=destiny_obj.is_public,
2118            crossave_override=destiny_obj.crossave_override,
2119            name=destiny_obj.name,
2120            last_seen_name=destiny_obj.last_seen_name,
2121            fireteam_display_name=payload["FireteamDisplayName"],
2122            fireteam_membership_id=enums.MembershipType(
2123                payload["FireteamMembershipType"]
2124            ),
2125        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: collections.abc.Mapping[str, typing.Any], *, alternatives: bool = False) -> collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]:
2127    def deserialize_fireteam_members(
2128        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2129    ) -> collections.Sequence[fireteams.FireteamMember]:
2130        members_: list[fireteams.FireteamMember] = []
2131        if members := payload.get("Members" if not alternatives else "Alternates"):
2132            for member in members:
2133                bungie_fields = self.deserialize_partial_bungie_user(member)
2134                members_fields = fireteams.FireteamMember(
2135                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2136                    has_microphone=member["hasMicrophone"],
2137                    character_id=int(member["characterId"]),
2138                    date_joined=time.clean_date(member["dateJoined"]),
2139                    last_platform_invite_date=time.clean_date(
2140                        member["lastPlatformInviteAttemptDate"]
2141                    ),
2142                    last_platform_invite_result=int(
2143                        member["lastPlatformInviteAttemptResult"]
2144                    ),
2145                    net=self._net,
2146                    name=bungie_fields.name,
2147                    id=bungie_fields.id,
2148                    icon=bungie_fields.icon,
2149                    is_public=bungie_fields.is_public,
2150                    crossave_override=bungie_fields.crossave_override,
2151                    types=bungie_fields.types,
2152                    type=bungie_fields.type,
2153                )
2154                members_.append(members_fields)
2155        return tuple(members_)

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteam( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.fireteams.AvailableFireteam:
2157    def deserialize_available_fireteam(
2158        self, payload: typedefs.JSONObject
2159    ) -> fireteams.AvailableFireteam:
2160        fields = self._set_fireteam_fields(payload["Summary"])
2161        return fireteams.AvailableFireteam(
2162            id=fields.id,
2163            group_id=fields.group_id,
2164            platform=fields.platform,
2165            activity_type=fields.activity_type,
2166            is_immediate=fields.is_immediate,
2167            is_public=fields.is_public,
2168            is_valid=fields.is_valid,
2169            owner_id=fields.owner_id,
2170            player_slot_count=fields.player_slot_count,
2171            available_player_slots=fields.available_player_slots,
2172            available_alternate_slots=fields.available_alternate_slots,
2173            title=fields.title,
2174            date_created=fields.date_created,
2175            locale=fields.locale,
2176            last_modified=fields.last_modified,
2177            total_results=fields.total_results,
2178            scheduled_time=fields.scheduled_time,
2179            date_modified=fields.date_modified,
2180            members=self.deserialize_fireteam_members(payload),
2181            alternatives=self.deserialize_fireteam_members(payload, alternatives=True),
2182        )

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
Returns
  • An available fireteam object.
def deserialize_available_fireteams( self, data: collections.abc.Mapping[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
2184    def deserialize_available_fireteams(
2185        self, data: typedefs.JSONObject
2186    ) -> collections.Sequence[fireteams.AvailableFireteam]:
2187        if raw_results := data.get("results"):
2188            fireteam_results = tuple(
2189                self.deserialize_available_fireteam(f) for f in raw_results
2190            )
2191        else:
2192            fireteam_results = ()
2193        return fireteam_results

Deserialize a JSON payload sequence of fireteam objects.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]: A sequence of available fireteams.
def deserialize_fireteam_party( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2195    def deserialize_fireteam_party(
2196        self, payload: typedefs.JSONObject
2197    ) -> fireteams.FireteamParty:
2198        last_destination_hash: int | None = None
2199        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2200            last_destination_hash = int(raw_dest_hash)
2201
2202        return fireteams.FireteamParty(
2203            members=tuple(
2204                self._deserialize_fireteam_party_member(member)
2205                for member in payload["partyMembers"]
2206            ),
2207            activity=self._deserialize_fireteam_party_current_activity(
2208                payload["currentActivity"]
2209            ),
2210            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2211            last_destination_hash=last_destination_hash,
2212            tracking=payload["tracking"],
2213        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2256    def deserialize_seasonal_artifact(
2257        self, payload: typedefs.JSONObject
2258    ) -> season.Artifact:
2259        raw_artifact = payload["seasonalArtifact"]
2260
2261        points = raw_artifact["pointProgression"]
2262        points_prog = progressions.Progression(
2263            hash=points["progressionHash"],
2264            level=points["level"],
2265            cap=points["levelCap"],
2266            daily_limit=points["dailyLimit"],
2267            weekly_limit=points["weeklyLimit"],
2268            current_progress=points["currentProgress"],
2269            daily_progress=points["dailyProgress"],
2270            needed=points["progressToNextLevel"],
2271            next_level=points["nextLevelAt"],
2272        )
2273
2274        bonus = raw_artifact["powerBonusProgression"]
2275        power_bonus_prog = progressions.Progression(
2276            hash=bonus["progressionHash"],
2277            level=bonus["level"],
2278            cap=bonus["levelCap"],
2279            daily_limit=bonus["dailyLimit"],
2280            weekly_limit=bonus["weeklyLimit"],
2281            current_progress=bonus["currentProgress"],
2282            daily_progress=bonus["dailyProgress"],
2283            needed=bonus["progressToNextLevel"],
2284            next_level=bonus["nextLevelAt"],
2285        )
2286        return season.Artifact(
2287            hash=raw_artifact["artifactHash"],
2288            power_bonus=raw_artifact["powerBonus"],
2289            acquired_points=raw_artifact["pointsAcquired"],
2290            bonus=power_bonus_prog,
2291            points=points_prog,
2292        )

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2294    def deserialize_profile_progression(
2295        self, payload: typedefs.JSONObject
2296    ) -> profile.ProfileProgression:
2297        return profile.ProfileProgression(
2298            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2299            checklist={
2300                int(check_id): checklists
2301                for check_id, checklists in payload["data"]["checklists"].items()
2302            },
2303        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2305    def deserialize_instanced_item(
2306        self, payload: typedefs.JSONObject
2307    ) -> items.ItemInstance:
2308        damage_type_hash: int | None = None
2309        if raw_damagetype_hash := payload.get("damageTypeHash"):
2310            damage_type_hash = int(raw_damagetype_hash)
2311
2312        required_hashes: typing.Optional[collections.Collection[int]] = None
2313        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2314            required_hashes = tuple(int(raw_hash) for raw_hash in raw_required_hashes)
2315
2316        breaker_type: items.ItemBreakerType | None = None
2317        if raw_break_type := payload.get("breakerType"):
2318            breaker_type = items.ItemBreakerType(int(raw_break_type))
2319
2320        breaker_type_hash: int | None = None
2321        if raw_break_type_hash := payload.get("breakerTypeHash"):
2322            breaker_type_hash = int(raw_break_type_hash)
2323
2324        energy: items.ItemEnergy | None = None
2325        if raw_energy := payload.get("energy"):
2326            energy = self.deserialize_item_energy(raw_energy)
2327
2328        primary_stats = None
2329        if raw_primary_stats := payload.get("primaryStat"):
2330            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2331
2332        return items.ItemInstance(
2333            damage_type=enums.DamageType(int(payload["damageType"])),
2334            damage_type_hash=damage_type_hash,
2335            primary_stat=primary_stats,
2336            item_level=int(payload["itemLevel"]),
2337            quality=int(payload["quality"]),
2338            is_equipped=payload["isEquipped"],
2339            can_equip=payload["canEquip"],
2340            equip_required_level=int(payload["equipRequiredLevel"]),
2341            required_equip_unlock_hashes=required_hashes,
2342            cant_equip_reason=int(payload["cannotEquipReason"]),
2343            breaker_type=breaker_type,
2344            breaker_type_hash=breaker_type_hash,
2345            energy=energy,
2346        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2348    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2349        energy_hash: int | None = None
2350        if raw_energy_hash := payload.get("energyTypeHash"):
2351            energy_hash = int(raw_energy_hash)
2352
2353        return items.ItemEnergy(
2354            hash=energy_hash,
2355            type=items.ItemEnergyType(int(payload["energyType"])),
2356            capacity=int(payload["energyCapacity"]),
2357            used_energy=int(payload["energyUsed"]),
2358            unused_energy=int(payload["energyUnused"]),
2359        )
def deserialize_item_perk( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2361    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2362        perk_hash: int | None = None
2363        if raw_perk_hash := payload.get("perkHash"):
2364            perk_hash = int(raw_perk_hash)
2365
2366        return items.ItemPerk(
2367            hash=perk_hash,
2368            icon=assets.Image(path=payload["iconPath"]),
2369            is_active=payload["isActive"],
2370            is_visible=payload["visible"],
2371        )
def deserialize_item_socket( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2373    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2374        plug_hash: int | None = None
2375        if raw_plug_hash := payload.get("plugHash"):
2376            plug_hash = int(raw_plug_hash)
2377
2378        enable_fail_indexes: collections.Sequence[int] | None = None
2379        if raw_indexes := payload.get("enableFailIndexes"):
2380            enable_fail_indexes = tuple(int(index) for index in raw_indexes)
2381
2382        return items.ItemSocket(
2383            plug_hash=plug_hash,
2384            is_enabled=payload["isEnabled"],
2385            enable_fail_indexes=enable_fail_indexes,
2386            is_visible=payload.get("visible"),
2387        )
def deserialize_item_stats_view( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2389    def deserialize_item_stats_view(
2390        self, payload: typedefs.JSONObject
2391    ) -> items.ItemStatsView:
2392        return items.ItemStatsView(
2393            stat_hash=payload.get("statHash"), value=payload.get("value")
2394        )
def deserialize_plug_item_state( self, payload: collections.abc.Mapping[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2396    def deserialize_plug_item_state(
2397        self, payload: typedefs.JSONObject
2398    ) -> items.PlugItemState:
2399        item_hash: int | None = None
2400        if raw_item_hash := payload.get("plugItemHash"):
2401            item_hash = int(raw_item_hash)
2402
2403        insert_fail_indexes: collections.Sequence[int] | None = None
2404        if raw_fail_indexes := payload.get("insertFailIndexes"):
2405            insert_fail_indexes = tuple(int(k) for k in raw_fail_indexes)
2406
2407        enable_fail_indexes: collections.Sequence[int] | None = None
2408        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2409            enable_fail_indexes = tuple(int(k) for k in raw_enabled_indexes)
2410
2411        return items.PlugItemState(
2412            item_hash=item_hash,
2413            insert_fail_indexes=insert_fail_indexes,
2414            enable_fail_indexes=enable_fail_indexes,
2415            is_enabled=payload["enabled"],
2416            can_insert=payload["canInsert"],
2417        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 65@typing.final
 66class FireteamActivity(int, enums.Enum):
 67    """An enum for the fireteam activities."""
 68
 69    ALL = 0
 70    CRUCIBLE = 2
 71    TRIALS_OF_OSIRIS = 3
 72    NIGHTFALL = 4
 73    ANY = 5
 74    GAMBIT = 6
 75    BLIND_WELL = 7
 76    NIGHTMARE_HUNTS = 12
 77    ALTARS_OF_SORROWS = 14
 78    DUNGEON = 15
 79    RAID_LW = 20
 80    RAID_GOS = 21
 81    RAID_DSC = 22
 82    EXO_CHALLENGE = 23
 83    S12_WRATHBORN = 24
 84    EMPIRE_HUNTS = 25
 85    S13_BATTLEGROUNDS = 26
 86    EXOTIC_QUEST = 27
 87    RAID_VOG = 28
 88    S14_EXPUNGE = 30
 89    S15_ASTRAL_ALIGNMENT = 31
 90    S15_SHATTERED_RELAM = 32
 91    SHATTERED_THRONE = 33
 92    PROPHECY = 34
 93    PIT_OF_HERESY = 35
 94    DOE = 36
 95    """Dares of Eternity."""
 96    DUNGEON_GOA = 37
 97    """Grasp of Avarice."""
 98    VOW_OF_THE_DISCPILE = 38
 99    CAMPAIGN = 39
100    WELLSPRING = 40
101    S16_BATTLEGROUNDS = 41
102    S17_NIGHTMARE_CONTAINMENT = 44
103    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
129@typing.final
130class FireteamDate(int, enums.Enum):
131    """An enum for fireteam date ranges."""
132
133    ALL = 0
134    NOW = 1
135    TODAY = 2
136    TWO_DAYS = 3
137    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
106@typing.final
107class FireteamLanguage(str, enums.Enum):
108    """An enum for fireteams languages filters."""
109
110    ALL = ""
111    ENGLISH = "en"
112    FRENCH = "fr"
113    ESPANOL = "es"
114    DEUTSCH = "de"
115    ITALIAN = "it"
116    JAPANESE = "ja"
117    PORTUGUESE = "pt-br"
118    RUSSIAN = "ru"
119    POLISH = "pl"
120    KOREAN = "ko"
121    # ? China
122    ZH_CHT = "zh-cht"
123    ZH_CHS = "zh-chs"
124
125    def __str__(self) -> str:
126        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
52@typing.final
53class FireteamPlatform(int, enums.Enum):
54    """An enum for fireteam related to bungie fireteams.
55    This is different from the normal `aiobungie.MembershipType`.
56    """
57
58    ANY = 0
59    PSN_NETWORK = 1
60    XBOX_LIVE = 2
61    STEAM = 4
62    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class Flag(enum.Flag):
 90class Flag(__enum.Flag):
 91    """Builtin Python enum flag with extra handlings."""
 92
 93    # Needs to type this here for mypy
 94    _value_: int
 95
 96    @property
 97    def name(self) -> str:
 98        if self._name_ is None:
 99            self._name_ = f"UNKNOWN {self._value_}"
100
101        return self._name_
102
103    @property
104    def value(self) -> int:
105        return self._value_
106
107    def __str__(self) -> str:
108        return self.name
109
110    def __repr__(self) -> str:
111        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
112
113    def __int__(self) -> int:
114        return int(self.value)
115
116    def __or__(self, other: Flag | int) -> Flag:
117        return self.__class__(self._value_ | int(other))
118
119    def __xor__(self, other: Flag | int) -> Flag:
120        return self.__class__(self._value_ ^ int(other))
121
122    def __and__(self, other: Flag | int) -> Flag:
123        return self.__class__(other & int(other))
124
125    def __invert__(self) -> Flag:
126        return self.__class__(~self._value_)
127
128    def __contains__(self, other: Flag | int) -> bool:
129        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str
 96    @property
 97    def name(self) -> str:
 98        if self._name_ is None:
 99            self._name_ = f"UNKNOWN {self._value_}"
100
101        return self._name_

The name of the Enum member.

value: int
103    @property
104    def value(self) -> int:
105        return self._value_

The value of the Enum member.

@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
136@attrs.define(auto_exc=True)
137class Forbidden(HTTPException):
138    """Exception that's raised for when status code 403 occurs."""
139
140    http_status: http.HTTPStatus = attrs.field(
141        default=http.HTTPStatus.FORBIDDEN, init=False
142    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
258@typing.final
259class GameMode(int, Enum):
260    """An Enum for all available gamemodes in Destiny 2."""
261
262    NONE = 0
263    STORY = 2
264    STRIKE = 3
265    RAID = 4
266    ALLPVP = 5
267    PATROL = 6
268    ALLPVE = 7
269    RESERVED9 = 9
270    CONTROL = 10
271    RESERVED11 = 11
272    CLASH = 12
273    RESERVED13 = 13
274    CRIMSONDOUBLES = 15
275    NIGHTFALL = 16
276    HEROICNIGHTFALL = 17
277    ALLSTRIKES = 18
278    IRONBANNER = 19
279    RESERVED20 = 20
280    RESERVED21 = 21
281    RESERVED22 = 22
282    RESERVED24 = 24
283    ALLMAYHEM = 25
284    RESERVED26 = 26
285    RESERVED27 = 27
286    RESERVED28 = 28
287    RESERVED29 = 29
288    RESERVED30 = 30
289    SUPREMACY = 31
290    PRIVATEMATCHESALL = 32
291    SURVIVAL = 37
292    COUNTDOWN = 38
293    TRIALSOFTHENINE = 39
294    SOCIAL = 40
295    TRIALSCOUNTDOWN = 41
296    TRIALSSURVIVAL = 42
297    IRONBANNERCONTROL = 43
298    IRONBANNERCLASH = 44
299    IRONBANNERSUPREMACY = 45
300    SCOREDNIGHTFALL = 46
301    SCOREDHEROICNIGHTFALL = 47
302    RUMBLE = 48
303    ALLDOUBLES = 49
304    DOUBLES = 50
305    PRIVATEMATCHESCLASH = 51
306    PRIVATEMATCHESCONTROL = 52
307    PRIVATEMATCHESSUPREMACY = 53
308    PRIVATEMATCHESCOUNTDOWN = 54
309    PRIVATEMATCHESSURVIVAL = 55
310    PRIVATEMATCHESMAYHEM = 56
311    PRIVATEMATCHESRUMBLE = 57
312    HEROICADVENTURE = 58
313    SHOWDOWN = 59
314    LOCKDOWN = 60
315    SCORCHED = 61
316    SCORCHEDTEAM = 62
317    GAMBIT = 63
318    ALLPVECOMPETITIVE = 64
319    BREAKTHROUGH = 65
320    BLACKARMORYRUN = 66
321    SALVAGE = 67
322    IRONBANNERSALVAGE = 68
323    PVPCOMPETITIVE = 69
324    PVPQUICKPLAY = 70
325    CLASHQUICKPLAY = 71
326    CLASHCOMPETITIVE = 72
327    CONTROLQUICKPLAY = 73
328    CONTROLCOMPETITIVE = 74
329    GAMBITPRIME = 75
330    RECKONING = 76
331    MENAGERIE = 77
332    VEXOFFENSIVE = 78
333    NIGHTMAREHUNT = 79
334    ELIMINATION = 80
335    MOMENTUM = 81
336    DUNGEON = 82
337    SUNDIAL = 83
338    TRIALS_OF_OSIRIS = 84
339    DARES = 85
340    OFFENSIVE = 86
341    LOSTSECTOR = 87
342    RIFT = 88
343    ZONECONTROL = 89
344    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
57@typing.final
58class GatingScope(int, enums.Enum):
59    """An enum represents restrictive type of gating that is being performed by an entity.
60
61    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
62    applies to everyone equally, or to their specific Profile or Character states.
63    """
64
65    NONE = 0
66    GLOBAL = 1
67    CLAN = 2
68    PROFILE = 3
69    CHARACTER = 4
70    ITEM = 5
71    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
476@typing.final
477class Gender(int, Enum):
478    """An Enum for Destiny Genders."""
479
480    MALE = 0
481    FEMALE = 1
482    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
645@typing.final
646class GroupType(int, Enum):
647    """An enums for the known bungie group types."""
648
649    GENERAL = 0
650    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
75@attrs.define(auto_exc=True)
76class HTTPError(AiobungieError):
77    """Base HTTP request errors exception."""
78
79    message: str
80    """The error message."""
81
82    http_status: http.HTTPStatus
83    """The response status."""

Base HTTP request errors exception.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 86@attrs.define(auto_exc=True, kw_only=True)
 87class HTTPException(HTTPError):
 88    """An in-depth HTTP exception that's raised with more information."""
 89
 90    error_code: int
 91    """The returned Bungie error status code."""
 92
 93    http_status: http.HTTPStatus
 94    """The request response http status."""
 95
 96    throttle_seconds: int
 97    """The Bungie response throttle seconds."""
 98
 99    url: typedefs.StrOrURL | None
100    """The URL/endpoint caused this error."""
101
102    body: typing.Any
103    """The response body."""
104
105    headers: multidict.CIMultiDictProxy[str]
106    """The response headers."""
107
108    message: str
109    """A Bungie human readable message describes the cause of the error."""
110
111    error_status: str
112    """A Bungie short error status describes the cause of the error."""
113
114    message_data: dict[str, str]
115    """A dict of string key, value that includes each cause of the error
116    to a message describes information about that error.
117    """
118
119    def __str__(self) -> str:
120        status_name, status_value = (
121            self.http_status.name.replace("_", "").title(),
122            self.http_status.value,
123        )
124        return (
125            f"{status_name}: " + "("
126            f"""
127            http_status: {status_value},
128            message: {self.message if self.message else 'UNDEFINED'},
129            error_status: {self.error_status if self.error_status else 'UNDEFINED'},
130            url: {self.url if self.url else 'UNDEFINED'},
131            message_data: {self.message_data}
132        """ + ")"
133        )

An in-depth HTTP exception that's raised with more information.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@attrs.frozen(kw_only=True, weakref_slot=False)
class Image:
 76@attrs.frozen(kw_only=True, weakref_slot=False)
 77class Image:
 78    """Representation of an image/avatar/picture Bungie resource.
 79
 80    Example
 81    -------
 82    ```py
 83    from aiobungie import Image
 84    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 85    print(img)
 86    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image..
 96    """
 97
 98    path: str = attrs.field()
 99
100    @property
101    def is_missing(self) -> bool:
102        return not self.path
103
104    @property
105    def url(self) -> str:
106        """The URL to the image."""
107        return self.create_url()
108
109    @staticmethod
110    def default() -> str:
111        """Returns the path to the missing Bungie image.
112
113        Note
114        ----
115        This returns the path only, If you want an actual image object use `Image.default_or_else()`
116        """
117        return "/img/misc/missing_icon_d2.png"
118
119    @classmethod
120    def default_or_else(cls, path: str | None = None) -> Self:
121        """Return the default image if `path` was `None` otherwise an `Image` object.
122
123        Example
124        -------
125        ```py
126        img = Image.default_or_else(None)
127        print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png
128
129        img = Image.default_or_else("/some_path/image.png")
130        ```
131        """
132        return cls(path=path or Image.default())
133
134    def create_url(self) -> str:
135        """Creates a full URL to the image path.
136
137        Returns
138        -------
139        str
140            The URL to the image.
141        """
142        return f"{url.BASE}/{self.path if self.path else self.default()}"
143
144    async def save(
145        self,
146        file_name: str,
147        path: pathlib.Path | str,
148        *,
149        mime_type: MimeType | str = MimeType.JPEG,
150        executor: concurrent.futures.Executor | None = None,
151    ) -> None:
152        """Saves the image to a file.
153
154        Parameters
155        ----------
156        file_name : `str`
157            A name for the file to save the image to.
158        path : `pathlib.Path | str`
159            A path tp save the image to.
160
161        Other Parameters
162        ----------------
163        mime_type : `MimeType | str`
164            MIME type of the image. Defaults to JPEG.
165        executor : `concurrent.futures.Executor | None`
166            An optional executor to use for writing the bytes of this image.
167
168        Raises
169        ------
170        `FileNotFoundError`
171            If the path provided does not exist.
172        `RuntimeError`
173            If the image could not be saved.
174        `PermissionError`
175            If the path provided is not writable or does not have write permissions.
176        """
177        if isinstance(path, pathlib.Path) and not path.exists():
178            raise FileNotFoundError(f"File does not exist: {path!r}")
179
180        if self.is_missing:
181            return
182
183        path = pathlib.Path(path)
184
185        loop = helpers.get_or_make_loop()
186
187        try:
188            await loop.run_in_executor(
189                executor, _write, path, file_name, mime_type, await self.read()
190            )
191            _LOGGER.info("Saved image to %s", file_name)
192
193        except asyncio.CancelledError:
194            pass
195
196        except Exception as err:
197            raise RuntimeError("Encountered an error while saving image.") from err
198
199    async def read(self) -> bytes:
200        """Read this image bytes.
201
202        Returns
203        -------
204        `bytes`
205            The bytes of this image.
206        """
207        client_session = aiohttp.ClientSession()
208
209        byte = b""
210        try:
211            await client_session.__aenter__()
212            response = await client_session.get(self.create_url())
213
214            if 300 >= response.status >= 200:
215                byte = await response.read()
216
217        except Exception as exc:
218            raise RuntimeError(f"Failed to read image: {exc}") from None
219        finally:
220            await client_session.__aexit__(None, None, None)
221        return byte
222
223    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
224        """Iterates over the image bytes lazily.
225
226        Example
227        -------
228        import aiobungie
229
230        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
231        async for chunk in resource.iter():
232            print(chunk)
233
234        Returns
235        -------
236        `collections.AsyncGenerator[bytes, None]`
237            An async generator of the image bytes.
238        """
239
240        async for chunk in self:
241            yield chunk
242
243    def __repr__(self) -> str:
244        return f"Image(url={self.create_url()})"
245
246    def __str__(self) -> str:
247        return self.create_url()
248
249    def __aiter__(self) -> Image:
250        return self
251
252    async def __anext__(self) -> bytes:
253        return await self.read()
254
255    def __await__(self) -> collections.Generator[None, None, bytes]:
256        return self.__anext__().__await__()

Representation of an image/avatar/picture Bungie resource.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image..
Image(*, path: str)
2def __init__(self, *, path):
3    _setattr = _cached_setattr_get(self)
4    _setattr('path', path)

Method generated by attrs for class Image.

path: str
is_missing: bool
100    @property
101    def is_missing(self) -> bool:
102        return not self.path
url: str
104    @property
105    def url(self) -> str:
106        """The URL to the image."""
107        return self.create_url()

The URL to the image.

@staticmethod
def default() -> str:
109    @staticmethod
110    def default() -> str:
111        """Returns the path to the missing Bungie image.
112
113        Note
114        ----
115        This returns the path only, If you want an actual image object use `Image.default_or_else()`
116        """
117        return "/img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

Note

This returns the path only, If you want an actual image object use Image.default_or_else()

@classmethod
def default_or_else(cls, path: str | None = None) -> 'Self':
119    @classmethod
120    def default_or_else(cls, path: str | None = None) -> Self:
121        """Return the default image if `path` was `None` otherwise an `Image` object.
122
123        Example
124        -------
125        ```py
126        img = Image.default_or_else(None)
127        print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png
128
129        img = Image.default_or_else("/some_path/image.png")
130        ```
131        """
132        return cls(path=path or Image.default())

Return the default image if path was None otherwise an Image object.

Example
img = Image.default_or_else(None)
print(img.url()) # https://www.bungie.net/img/misc/missing_icon_d2.png

img = Image.default_or_else("/some_path/image.png")
def create_url(self) -> str:
134    def create_url(self) -> str:
135        """Creates a full URL to the image path.
136
137        Returns
138        -------
139        str
140            The URL to the image.
141        """
142        return f"{url.BASE}/{self.path if self.path else self.default()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: pathlib.Path | str, *, mime_type: aiobungie.internal.assets.MimeType | str = <MimeType.JPEG: jpeg>, executor: concurrent.futures._base.Executor | None = None) -> None:
144    async def save(
145        self,
146        file_name: str,
147        path: pathlib.Path | str,
148        *,
149        mime_type: MimeType | str = MimeType.JPEG,
150        executor: concurrent.futures.Executor | None = None,
151    ) -> None:
152        """Saves the image to a file.
153
154        Parameters
155        ----------
156        file_name : `str`
157            A name for the file to save the image to.
158        path : `pathlib.Path | str`
159            A path tp save the image to.
160
161        Other Parameters
162        ----------------
163        mime_type : `MimeType | str`
164            MIME type of the image. Defaults to JPEG.
165        executor : `concurrent.futures.Executor | None`
166            An optional executor to use for writing the bytes of this image.
167
168        Raises
169        ------
170        `FileNotFoundError`
171            If the path provided does not exist.
172        `RuntimeError`
173            If the image could not be saved.
174        `PermissionError`
175            If the path provided is not writable or does not have write permissions.
176        """
177        if isinstance(path, pathlib.Path) and not path.exists():
178            raise FileNotFoundError(f"File does not exist: {path!r}")
179
180        if self.is_missing:
181            return
182
183        path = pathlib.Path(path)
184
185        loop = helpers.get_or_make_loop()
186
187        try:
188            await loop.run_in_executor(
189                executor, _write, path, file_name, mime_type, await self.read()
190            )
191            _LOGGER.info("Saved image to %s", file_name)
192
193        except asyncio.CancelledError:
194            pass
195
196        except Exception as err:
197            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): MIME type of the image. Defaults to JPEG.
  • executor (concurrent.futures.Executor | None): An optional executor to use for writing the bytes of this image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
199    async def read(self) -> bytes:
200        """Read this image bytes.
201
202        Returns
203        -------
204        `bytes`
205            The bytes of this image.
206        """
207        client_session = aiohttp.ClientSession()
208
209        byte = b""
210        try:
211            await client_session.__aenter__()
212            response = await client_session.get(self.create_url())
213
214            if 300 >= response.status >= 200:
215                byte = await response.read()
216
217        except Exception as exc:
218            raise RuntimeError(f"Failed to read image: {exc}") from None
219        finally:
220            await client_session.__aexit__(None, None, None)
221        return byte

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
223    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
224        """Iterates over the image bytes lazily.
225
226        Example
227        -------
228        import aiobungie
229
230        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
231        async for chunk in resource.iter():
232            print(chunk)
233
234        Returns
235        -------
236        `collections.AsyncGenerator[bytes, None]`
237            An async generator of the image bytes.
238        """
239
240        async for chunk in self:
241            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
240@attrs.define(auto_exc=True)
241class InternalServerError(HTTPException):
242    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
711@typing.final
712class ItemBindStatus(int, Enum):
713    """An enum for Destiny 2 items bind status."""
714
715    NOT_BOUND = 0
716    BOUND_TO_CHARACTER = 1
717    BOUND_TO_ACCOUNT = 2
718    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
721@typing.final
722class ItemLocation(int, Enum):
723    """An enum for Destiny 2 items location."""
724
725    UNKNOWN = 0
726    INVENTORY = 1
727    VAULT = 2
728    VENDOR = 3
729    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
746@typing.final
747class ItemState(Flag):
748    """An enum for Destiny 2 item states."""
749
750    NONE = 0
751    LOCKED = 1 << 0
752    TRACKED = 1 << 1
753    MASTERWORKED = 1 << 2
754    CRAFTED = 1 << 3
755    """If this bit is set, the item has been 'crafted' by the player."""
756    HIGHLITED_OBJECTIVE = 1 << 4
757    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
578@typing.final
579class ItemSubType(int, Enum):
580    """An enum for Destiny 2 inventory items subtype."""
581
582    NONE = 0
583    AUTORIFLE = 6
584    SHOTGUN = 7
585    MACHINEGUN = 8
586    HANDCANNON = 9
587    ROCKETLAUNCHER = 10
588    FUSIONRIFLE = 11
589    SNIPERRIFLE = 12
590    PULSERIFLE = 13
591    SCOUTRIFLE = 14
592    SIDEARM = 17
593    SWORD = 18
594    MASK = 19
595    SHADER = 20
596    ORNAMENT = 21
597    FUSIONRIFLELINE = 22
598    GRENADELAUNCHER = 23
599    SUBMACHINEGUN = 24
600    TRACERIFLE = 25
601    HELMETARMOR = 26
602    GAUNTLETSARMOR = 27
603    CHESTARMOR = 28
604    LEGARMOR = 29
605    CLASSARMOR = 30
606    BOW = 31
607    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
610@typing.final
611class ItemTier(int, Enum):
612    """An enum for a Destiny 2 item tier."""
613
614    NONE = 0
615    BASIC = 3340296461
616    COMMON = 2395677314
617    RARE = 2127292149
618    LEGENDERY = 4008398120
619    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
545@typing.final
546class ItemType(int, Enum):
547    """Enums for Destiny2's item types."""
548
549    NONE = 0
550    CURRENCY = 1
551    ARMOR = 2
552    WEAPON = 3
553    MESSAGE = 7
554    ENGRAM = 8
555    CONSUMABLE = 9
556    EXCHANGEMATERIAL = 10
557    MISSIONREWARD = 11
558    QUESTSTEP = 12
559    QUESTSTEPCOMPLETE = 13
560    EMBLEM = 14
561    QUEST = 15
562    SUBCLASS = 16
563    CLANBANNER = 17
564    AURA = 18
565    MOD = 19
566    DUMMY = 20
567    SHIP = 21
568    VEHICLE = 22
569    EMOTE = 23
570    GHOST = 24
571    PACKAGE = 25
572    BOUNTY = 26
573    WRAPPER = 27
574    SEASONALARTIFACT = 28
575    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class Iterator(typing.Generic[~Item], collections.abc.Iterator[~Item]):
 47class Iterator(typing.Generic[Item], collections.Iterator[Item]):
 48    """A Flat, In-Memory iterator for sequenced based data.
 49
 50    Example
 51    -------
 52    ```py
 53    iterator = Iterator([1, 2, 3])
 54
 55    # Map the results.
 56    for item in iterator.map(lambda item: item * 2):
 57        print(item)
 58    # 2
 59    # 4
 60
 61    # Indexing is also supported.
 62    print(iterator[0])
 63    # 1
 64
 65    # Normal iteration.
 66    for item in iterator:
 67        print(item)
 68    # 1
 69    # 2
 70    # 3
 71
 72    # Union two iterators.
 73    iterator2 = Iterator([4, 5, 6])
 74    final = iterator | iterator2
 75    # <Iterator([1, 2, 3, 4, 5, 6])>
 76    ```
 77
 78    Parameters
 79    ----------
 80    items: `collections.Iterable[Item]`
 81        The items to iterate over.
 82    """
 83
 84    __slots__ = ("_items",)
 85
 86    def __init__(self, items: collections.Iterable[Item]) -> None:
 87        self._items = _builtins.iter(items)
 88
 89    @typing.overload
 90    def collect(self) -> collections.Sequence[Item]:
 91        ...
 92
 93    @typing.overload
 94    def collect(self, casting: _B) -> collections.Sequence[_B]:
 95        ...
 96
 97    def collect(
 98        self, casting: _B | None = None
 99    ) -> collections.Sequence[Item] | collections.Sequence[_B]:
100        """Collects all items in the iterator into an immutable collection.
101
102        Example
103        -------
104        >>> iterator = Iterator([1, 2, 3])
105        >>> iterator.collect(casting=str)
106        ("1", "2", "3")
107
108        Parameters
109        ----------
110        casting: `T | None`
111            The type to cast the items to. If `None` is provided, the items will be returned as is.
112
113        Returns
114        -------
115        `collections.Sequence[Item | T]`
116            An immutable sequence of the elements in the iterator.
117
118        Raises
119        ------
120        `StopIteration`
121            If no elements are left in the iterator.
122        """
123        if casting is not None:
124            return typing.cast(
125                collections.Sequence[_B], tuple(map(casting, self._items))
126            )
127
128        return tuple(self._items)
129
130    def copied(self) -> Iterator[Item]:
131        """Creates an iterator which `deeply` copies all of its elements.
132
133        .. warn::
134            This will `deeply` copy all of the elements, Use `Iterator.by_ref`
135            if you want copy of the iterator reference.
136
137        Example
138        -------
139        ```py
140        it = Iterator([None, None, None])
141        copied_iter = it.copied()
142        assert it.collect() == copied.collect()
143        ```
144        """
145        return Iterator(_copy.deepcopy(self._items))
146
147    def by_ref(self) -> Iterator[Item]:
148        """Creates an iterator which doesn't consume its elements.
149        but instead shallow copy it.
150
151        Example
152        -------
153        ```py
154        it = Iterator([None, None, None])
155        for ref in it.by_ref():
156            ...
157
158        # Original not consumed.
159        assert it.count() == 3
160        ```
161        """
162        return Iterator(_copy.copy(self._items))
163
164    def next(self) -> Item:
165        """Returns the next item in the iterator.
166
167        Example
168        -------
169        ```py
170        iterator = Iterator(["1", "2", "3"])
171        item = iterator.next()
172        assert item == "1"
173        item = iterator.next()
174        assert item == "2"
175        ```
176
177        Raises
178        ------
179        `StopIteration`
180            If no elements are left in the iterator.
181        """
182        try:
183            return self.__next__()
184        except StopIteration:
185            self._ok()
186
187    def map(
188        self, predicate: collections.Callable[[Item], OtherItem]
189    ) -> Iterator[OtherItem]:
190        """Maps each item in the iterator to its predicated value.
191
192        Example
193        -------
194        ```py
195        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
196        print(iterator)
197        # <Iterator([1, 2, 3])>
198        ```
199
200        Parameters
201        ----------
202        predicate: `collections.Callable[[Item], OtherItem]`
203            The function to map each item in the iterator to its predicated value.
204
205        Returns
206        -------
207        `Iterator[OtherItem]`
208            The mapped iterator.
209
210        Raises
211        ------
212        `StopIteration`
213            If no elements are left in the iterator.
214        """
215        return Iterator(map(predicate, self._items))
216
217    def take(self, n: int) -> Iterator[Item]:
218        """Take the first number of items until the number of items are yielded or
219        the end of the iterator is reached.
220
221        Example
222        -------
223        ```py
224        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
225        print(iterator.take(2))
226        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
227        ```
228
229        Parameters
230        ----------
231        n: `int`
232            The number of items to take.
233
234        Raises
235        ------
236        `StopIteration`
237            If no elements are left in the iterator.
238        """
239        return Iterator(itertools.islice(self._items, n))
240
241    def take_while(
242        self, predicate: collections.Callable[[Item], bool]
243    ) -> Iterator[Item]:
244        """Yields items from the iterator while predicate returns `True`.
245
246        Example
247        -------
248        ```py
249        iterator = Iterator([STEAM, XBOX, STADIA])
250        print(iterator.take_while(lambda platform: platform is not XBOX))
251        # <Iterator([STEAM])>
252        ```
253
254        Parameters
255        ----------
256        predicate: `collections.Callable[[Item], bool]`
257            The function to predicate each item in the iterator.
258
259        Raises
260        ------
261        `StopIteration`
262            If no elements are left in the iterator.
263        """
264        return Iterator(itertools.takewhile(predicate, self._items))
265
266    def drop_while(
267        self, predicate: collections.Callable[[Item], bool]
268    ) -> Iterator[Item]:
269        """Yields items from the iterator while predicate returns `False`.
270
271        Example
272        -------
273        ```py
274        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
275        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
276        # <Iterator([DestinyMembership(name="Bob")])>
277        ```
278
279        Parameters
280        ----------
281        predicate: `collections.Callable[[Item], bool]`
282            The function to predicate each item in the iterator.
283
284        Raises
285        ------
286        `StopIteration`
287            If no elements are left in the iterator.
288        """
289        return Iterator(itertools.dropwhile(predicate, self._items))
290
291    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
292        """Filters the iterator to only yield items that match the predicate.
293
294        Example
295        -------
296        ```py
297        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
298        print(names.filter(lambda n: n != "Jim"))
299        # <Iterator(["Bob", "Mike", "Jess"])>
300        ```
301        """
302        return Iterator(filter(predicate, self._items))
303
304    def skip(self, n: int) -> Iterator[Item]:
305        """Skips the first number of items in the iterator.
306
307        Example
308        -------
309        ```py
310        iterator = Iterator([STEAM, XBOX, STADIA])
311        print(iterator.skip(1))
312        # <Iterator([XBOX, STADIA])>
313        ```
314        """
315        return Iterator(itertools.islice(self._items, n, None))
316
317    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
318        """Zips the iterator with another iterable.
319
320        Example
321        -------
322        ```py
323        iterator = Iterator([1, 3, 5])
324        other = Iterator([2, 4, 6])
325        for item, other_item in iterator.zip(other):
326            print(item, other_item)
327        # <Iterator([(1, 2), (3, 4), (5, 6)])>
328        ```
329
330        Parameters
331        ----------
332        other: `Iterator[OtherItem]`
333            The iterable to zip with.
334
335        Raises
336        ------
337        `StopIteration`
338            If no elements are left in the iterator.
339        """
340        return Iterator(zip(self._items, other))
341
342    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
343        """`True` if all items in the iterator match the predicate.
344
345        Example
346        -------
347        ```py
348        iterator = Iterator([1, 2, 3])
349        while iterator.all(lambda item: isinstance(item, int)):
350            print("Still all integers")
351            continue
352        # Still all integers
353        ```
354
355        Parameters
356        ----------
357        predicate: `collections.Callable[[Item], bool]`
358            The function to test each item in the iterator.
359
360        Raises
361        ------
362        `StopIteration`
363            If no elements are left in the iterator.
364        """
365        return all(predicate(item) for item in self)
366
367    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
368        """`True` if any items in the iterator match the predicate.
369
370        Example
371        -------
372        ```py
373        iterator = Iterator([1, 2, 3])
374        if iterator.any(lambda item: isinstance(item, int)):
375            print("At least one item is an int.")
376        # At least one item is an int.
377        ```
378
379        Parameters
380        ----------
381        predicate: `collections.Callable[[Item], bool]`
382            The function to test each item in the iterator.
383
384        Raises
385        ------
386        `StopIteration`
387            If no elements are left in the iterator.
388        """
389        return any(predicate(item) for item in self)
390
391    def sort(
392        self,
393        *,
394        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
395        reverse: bool = False,
396    ) -> Iterator[Item]:
397        """Sorts the iterator.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.sort(key=lambda item: item))
404        # <Iterator([1, 3, 6, 7])>
405        ```
406
407        Parameters
408        ----------
409        key: `collections.Callable[[Item], Any]`
410            The function to sort by.
411        reverse: `bool`
412            Whether to reverse the sort.
413
414        Raises
415        ------
416        `StopIteration`
417            If no elements are left in the iterator.
418        """
419        return Iterator(sorted(self._items, key=key, reverse=reverse))
420
421    def first(self) -> Item:
422        """Returns the first item in the iterator.
423
424        Example
425        -------
426        ```py
427        iterator = Iterator([3, 1, 6, 7])
428        print(iterator.first())
429        3
430        ```
431
432        Raises
433        ------
434        `StopIteration`
435            If no elements are left in the iterator.
436        """
437        return self.take(1).next()
438
439    def last(self) -> Item:
440        """Returns the last item in the iterator.
441
442        Example
443        ------
444        ```py
445        it = Iterator((1, 2, 3))
446        assert it.first() == 1 and it.last() == 3
447        ```
448        """
449        return self.reversed().first()
450
451    def reversed(self) -> Iterator[Item]:
452        """Returns a new iterator that yields the items in the iterator in reverse order.
453
454        Example
455        -------
456        ```py
457        iterator = Iterator([3, 1, 6, 7])
458        print(iterator.reversed())
459        # <Iterator([7, 6, 1, 3])>
460        ```
461
462        Raises
463        ------
464        `StopIteration`
465            If no elements are left in the iterator.
466        """
467        return Iterator(reversed(self.collect()))
468
469    def count(self) -> int:
470        """Returns the number of items in the iterator.
471
472        Example
473        -------
474        ```py
475        iterator = Iterator([3, 1, 6, 7])
476        print(iterator.count())
477        4
478        ```
479        """
480        count = 0
481        for _ in self:
482            count += 1
483
484        return count
485
486    def union(self, other: Iterator[Item]) -> Iterator[Item]:
487        """Returns a new iterator that yields all items from both iterators.
488
489        Example
490        -------
491        ```py
492        iterator = Iterator([1, 2, 3])
493        other = Iterator([4, 5, 6])
494        print(iterator.union(other))
495        # <Iterator([1, 2, 3, 4, 5, 6])>
496        ```
497
498        Parameters
499        ----------
500        other: `Iterator[Item]`
501            The iterable to union with.
502
503        Raises
504        ------
505        `StopIteration`
506            If no elements are left in the iterator.
507        """
508        return Iterator(itertools.chain(self._items, other))
509
510    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
511        """Calls the function on each item in the iterator.
512
513        Example
514        -------
515        ```py
516        iterator = Iterator([1, 2, 3])
517        iterator.for_each(lambda item: print(item))
518        # 1
519        # 2
520        # 3
521        ```
522
523        Parameters
524        ----------
525        func: `typeshed.Callable[[Item], None]`
526            The function to call on each item in the iterator.
527        """
528        for item in self:
529            func(item)
530
531    async def async_for_each(
532        self,
533        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
534    ) -> None:
535        """Calls the async function on each item in the iterator concurrently.
536
537        Example
538        -------
539        ```py
540        async def signup(username: str) -> None:
541            async with aiohttp.request('POST', '...') as r:
542                # Actual logic.
543                ...
544
545        async def main():
546            users = aiobungie.into_iter(["user_danny", "user_jojo"])
547            await users.async_for_each(lambda username: signup(username))
548        ```
549
550        Parameters
551        ----------
552        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
553            The async function to call on each item in the iterator.
554        """
555        await _helpers.awaits(*(func(item) for item in self))
556
557    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
558        """Returns a new iterator that yields tuples of the index and item.
559
560        Example
561        -------
562        ```py
563        iterator = Iterator([1, 2, 3])
564        for index, item in iterator.enumerate():
565            print(index, item)
566        # 0 1
567        # 1 2
568        # 2 3
569        ```
570
571        Raises
572        ------
573        `StopIteration`
574            If no elements are left in the iterator.
575        """
576        return Iterator(enumerate(self._items, start=start))
577
578    def _ok(self) -> typing.NoReturn:
579        raise StopIteration("No more items in the iterator.") from None
580
581    def __getitem__(self, index: int) -> Item:
582        try:
583            return self.skip(index).first()
584        except IndexError:
585            self._ok()
586
587    def __or__(self, other: Iterator[Item]) -> Iterator[Item]:
588        return self.union(other)
589
590    # This is a never.
591    def __setitem__(self) -> typing.NoReturn:
592        raise TypeError(
593            f"{type(self).__name__} doesn't support item assignment."
594        ) from None
595
596    def __repr__(self) -> str:
597        return f"Iterator(ptr: {hex(id(self._items))})"
598
599    __str__ = __repr__
600
601    def __len__(self) -> int:
602        return self.count()
603
604    def __iter__(self) -> Iterator[Item]:
605        return self
606
607    def __next__(self) -> Item:
608        try:
609            item = next(self._items)
610        except StopIteration:
611            self._ok()
612
613        return item

A Flat, In-Memory iterator for sequenced based data.

Example
iterator = Iterator([1, 2, 3])

# Map the results.
for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# Indexing is also supported.
print(iterator[0])
# 1

# Normal iteration.
for item in iterator:
    print(item)
# 1
# 2
# 3

# Union two iterators.
iterator2 = Iterator([4, 5, 6])
final = iterator | iterator2
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
Iterator(items: collections.abc.Iterable[~Item])
86    def __init__(self, items: collections.Iterable[Item]) -> None:
87        self._items = _builtins.iter(items)
def collect( self, casting: '_B | None' = None) -> 'collections.Sequence[Item] | collections.Sequence[_B]':
 97    def collect(
 98        self, casting: _B | None = None
 99    ) -> collections.Sequence[Item] | collections.Sequence[_B]:
100        """Collects all items in the iterator into an immutable collection.
101
102        Example
103        -------
104        >>> iterator = Iterator([1, 2, 3])
105        >>> iterator.collect(casting=str)
106        ("1", "2", "3")
107
108        Parameters
109        ----------
110        casting: `T | None`
111            The type to cast the items to. If `None` is provided, the items will be returned as is.
112
113        Returns
114        -------
115        `collections.Sequence[Item | T]`
116            An immutable sequence of the elements in the iterator.
117
118        Raises
119        ------
120        `StopIteration`
121            If no elements are left in the iterator.
122        """
123        if casting is not None:
124            return typing.cast(
125                collections.Sequence[_B], tuple(map(casting, self._items))
126            )
127
128        return tuple(self._items)

Collects all items in the iterator into an immutable collection.

Example
>>> iterator = Iterator([1, 2, 3])
>>> iterator.collect(casting=str)
("1", "2", "3")
Parameters
  • casting (T | None): The type to cast the items to. If None is provided, the items will be returned as is.
Returns
  • collections.Sequence[Item | T]: An immutable sequence of the elements in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def copied(self) -> Iterator[~Item]:
130    def copied(self) -> Iterator[Item]:
131        """Creates an iterator which `deeply` copies all of its elements.
132
133        .. warn::
134            This will `deeply` copy all of the elements, Use `Iterator.by_ref`
135            if you want copy of the iterator reference.
136
137        Example
138        -------
139        ```py
140        it = Iterator([None, None, None])
141        copied_iter = it.copied()
142        assert it.collect() == copied.collect()
143        ```
144        """
145        return Iterator(_copy.deepcopy(self._items))

Creates an iterator which deeply copies all of its elements.

.. warn:: This will deeply copy all of the elements, Use Iterator.by_ref if you want copy of the iterator reference.

Example
it = Iterator([None, None, None])
copied_iter = it.copied()
assert it.collect() == copied.collect()
def by_ref(self) -> Iterator[~Item]:
147    def by_ref(self) -> Iterator[Item]:
148        """Creates an iterator which doesn't consume its elements.
149        but instead shallow copy it.
150
151        Example
152        -------
153        ```py
154        it = Iterator([None, None, None])
155        for ref in it.by_ref():
156            ...
157
158        # Original not consumed.
159        assert it.count() == 3
160        ```
161        """
162        return Iterator(_copy.copy(self._items))

Creates an iterator which doesn't consume its elements. but instead shallow copy it.

Example
it = Iterator([None, None, None])
for ref in it.by_ref():
    ...

# Original not consumed.
assert it.count() == 3
def next(self) -> ~Item:
164    def next(self) -> Item:
165        """Returns the next item in the iterator.
166
167        Example
168        -------
169        ```py
170        iterator = Iterator(["1", "2", "3"])
171        item = iterator.next()
172        assert item == "1"
173        item = iterator.next()
174        assert item == "2"
175        ```
176
177        Raises
178        ------
179        `StopIteration`
180            If no elements are left in the iterator.
181        """
182        try:
183            return self.__next__()
184        except StopIteration:
185            self._ok()

Returns the next item in the iterator.

Example
iterator = Iterator(["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'Iterator[OtherItem]':
187    def map(
188        self, predicate: collections.Callable[[Item], OtherItem]
189    ) -> Iterator[OtherItem]:
190        """Maps each item in the iterator to its predicated value.
191
192        Example
193        -------
194        ```py
195        iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
196        print(iterator)
197        # <Iterator([1, 2, 3])>
198        ```
199
200        Parameters
201        ----------
202        predicate: `collections.Callable[[Item], OtherItem]`
203            The function to map each item in the iterator to its predicated value.
204
205        Returns
206        -------
207        `Iterator[OtherItem]`
208            The mapped iterator.
209
210        Raises
211        ------
212        `StopIteration`
213            If no elements are left in the iterator.
214        """
215        return Iterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
iterator = Iterator(["1", "2", "3"]).map(lambda value: int(value))
print(iterator)
# <Iterator([1, 2, 3])>
Parameters
  • predicate (collections.Callable[[Item], OtherItem]): The function to map each item in the iterator to its predicated value.
Returns
  • Iterator[OtherItem]: The mapped iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> Iterator[~Item]:
217    def take(self, n: int) -> Iterator[Item]:
218        """Take the first number of items until the number of items are yielded or
219        the end of the iterator is reached.
220
221        Example
222        -------
223        ```py
224        iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
225        print(iterator.take(2))
226        # <Iterator([GameMode.RAID, GameMode.STRIKE])>
227        ```
228
229        Parameters
230        ----------
231        n: `int`
232            The number of items to take.
233
234        Raises
235        ------
236        `StopIteration`
237            If no elements are left in the iterator.
238        """
239        return Iterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
iterator = Iterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
print(iterator.take(2))
# <Iterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
241    def take_while(
242        self, predicate: collections.Callable[[Item], bool]
243    ) -> Iterator[Item]:
244        """Yields items from the iterator while predicate returns `True`.
245
246        Example
247        -------
248        ```py
249        iterator = Iterator([STEAM, XBOX, STADIA])
250        print(iterator.take_while(lambda platform: platform is not XBOX))
251        # <Iterator([STEAM])>
252        ```
253
254        Parameters
255        ----------
256        predicate: `collections.Callable[[Item], bool]`
257            The function to predicate each item in the iterator.
258
259        Raises
260        ------
261        `StopIteration`
262            If no elements are left in the iterator.
263        """
264        return Iterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.take_while(lambda platform: platform is not XBOX))
# <Iterator([STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
266    def drop_while(
267        self, predicate: collections.Callable[[Item], bool]
268    ) -> Iterator[Item]:
269        """Yields items from the iterator while predicate returns `False`.
270
271        Example
272        -------
273        ```py
274        iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
275        print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
276        # <Iterator([DestinyMembership(name="Bob")])>
277        ```
278
279        Parameters
280        ----------
281        predicate: `collections.Callable[[Item], bool]`
282            The function to predicate each item in the iterator.
283
284        Raises
285        ------
286        `StopIteration`
287            If no elements are left in the iterator.
288        """
289        return Iterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = Iterator([DestinyMembership(name="Jim"), DestinyMembership(name="Bob")])
print(iterator.drop_while(lambda membership: membership.name is not "Jim"))
# <Iterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> Iterator[~Item]:
291    def filter(self, predicate: collections.Callable[[Item], bool]) -> Iterator[Item]:
292        """Filters the iterator to only yield items that match the predicate.
293
294        Example
295        -------
296        ```py
297        names = Iterator(["Jim", "Bob", "Mike", "Jess"])
298        print(names.filter(lambda n: n != "Jim"))
299        # <Iterator(["Bob", "Mike", "Jess"])>
300        ```
301        """
302        return Iterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
names = Iterator(["Jim", "Bob", "Mike", "Jess"])
print(names.filter(lambda n: n != "Jim"))
# <Iterator(["Bob", "Mike", "Jess"])>
def skip(self, n: int) -> Iterator[~Item]:
304    def skip(self, n: int) -> Iterator[Item]:
305        """Skips the first number of items in the iterator.
306
307        Example
308        -------
309        ```py
310        iterator = Iterator([STEAM, XBOX, STADIA])
311        print(iterator.skip(1))
312        # <Iterator([XBOX, STADIA])>
313        ```
314        """
315        return Iterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example
iterator = Iterator([STEAM, XBOX, STADIA])
print(iterator.skip(1))
# <Iterator([XBOX, STADIA])>
def zip(self, other: 'Iterator[OtherItem]') -> 'Iterator[tuple[Item, OtherItem]]':
317    def zip(self, other: Iterator[OtherItem]) -> Iterator[tuple[Item, OtherItem]]:
318        """Zips the iterator with another iterable.
319
320        Example
321        -------
322        ```py
323        iterator = Iterator([1, 3, 5])
324        other = Iterator([2, 4, 6])
325        for item, other_item in iterator.zip(other):
326            print(item, other_item)
327        # <Iterator([(1, 2), (3, 4), (5, 6)])>
328        ```
329
330        Parameters
331        ----------
332        other: `Iterator[OtherItem]`
333            The iterable to zip with.
334
335        Raises
336        ------
337        `StopIteration`
338            If no elements are left in the iterator.
339        """
340        return Iterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
iterator = Iterator([1, 3, 5])
other = Iterator([2, 4, 6])
for item, other_item in iterator.zip(other):
    print(item, other_item)
# <Iterator([(1, 2), (3, 4), (5, 6)])>
Parameters
  • other (Iterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
342    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
343        """`True` if all items in the iterator match the predicate.
344
345        Example
346        -------
347        ```py
348        iterator = Iterator([1, 2, 3])
349        while iterator.all(lambda item: isinstance(item, int)):
350            print("Still all integers")
351            continue
352        # Still all integers
353        ```
354
355        Parameters
356        ----------
357        predicate: `collections.Callable[[Item], bool]`
358            The function to test each item in the iterator.
359
360        Raises
361        ------
362        `StopIteration`
363            If no elements are left in the iterator.
364        """
365        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
while iterator.all(lambda item: isinstance(item, int)):
    print("Still all integers")
    continue
# Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
367    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
368        """`True` if any items in the iterator match the predicate.
369
370        Example
371        -------
372        ```py
373        iterator = Iterator([1, 2, 3])
374        if iterator.any(lambda item: isinstance(item, int)):
375            print("At least one item is an int.")
376        # At least one item is an int.
377        ```
378
379        Parameters
380        ----------
381        predicate: `collections.Callable[[Item], bool]`
382            The function to test each item in the iterator.
383
384        Raises
385        ------
386        `StopIteration`
387            If no elements are left in the iterator.
388        """
389        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
iterator = Iterator([1, 2, 3])
if iterator.any(lambda item: isinstance(item, int)):
    print("At least one item is an int.")
# At least one item is an int.
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> Iterator[~Item]:
391    def sort(
392        self,
393        *,
394        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
395        reverse: bool = False,
396    ) -> Iterator[Item]:
397        """Sorts the iterator.
398
399        Example
400        -------
401        ```py
402        iterator = Iterator([3, 1, 6, 7])
403        print(iterator.sort(key=lambda item: item))
404        # <Iterator([1, 3, 6, 7])>
405        ```
406
407        Parameters
408        ----------
409        key: `collections.Callable[[Item], Any]`
410            The function to sort by.
411        reverse: `bool`
412            Whether to reverse the sort.
413
414        Raises
415        ------
416        `StopIteration`
417            If no elements are left in the iterator.
418        """
419        return Iterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.sort(key=lambda item: item))
# <Iterator([1, 3, 6, 7])>
Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
421    def first(self) -> Item:
422        """Returns the first item in the iterator.
423
424        Example
425        -------
426        ```py
427        iterator = Iterator([3, 1, 6, 7])
428        print(iterator.first())
429        3
430        ```
431
432        Raises
433        ------
434        `StopIteration`
435            If no elements are left in the iterator.
436        """
437        return self.take(1).next()

Returns the first item in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.first())
3
Raises
  • StopIteration: If no elements are left in the iterator.
def last(self) -> ~Item:
439    def last(self) -> Item:
440        """Returns the last item in the iterator.
441
442        Example
443        ------
444        ```py
445        it = Iterator((1, 2, 3))
446        assert it.first() == 1 and it.last() == 3
447        ```
448        """
449        return self.reversed().first()

Returns the last item in the iterator.

Example
it = Iterator((1, 2, 3))
assert it.first() == 1 and it.last() == 3
def reversed(self) -> Iterator[~Item]:
451    def reversed(self) -> Iterator[Item]:
452        """Returns a new iterator that yields the items in the iterator in reverse order.
453
454        Example
455        -------
456        ```py
457        iterator = Iterator([3, 1, 6, 7])
458        print(iterator.reversed())
459        # <Iterator([7, 6, 1, 3])>
460        ```
461
462        Raises
463        ------
464        `StopIteration`
465            If no elements are left in the iterator.
466        """
467        return Iterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.reversed())
# <Iterator([7, 6, 1, 3])>
Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
469    def count(self) -> int:
470        """Returns the number of items in the iterator.
471
472        Example
473        -------
474        ```py
475        iterator = Iterator([3, 1, 6, 7])
476        print(iterator.count())
477        4
478        ```
479        """
480        count = 0
481        for _ in self:
482            count += 1
483
484        return count

Returns the number of items in the iterator.

Example
iterator = Iterator([3, 1, 6, 7])
print(iterator.count())
4
def union( self, other: Iterator[~Item]) -> Iterator[~Item]:
486    def union(self, other: Iterator[Item]) -> Iterator[Item]:
487        """Returns a new iterator that yields all items from both iterators.
488
489        Example
490        -------
491        ```py
492        iterator = Iterator([1, 2, 3])
493        other = Iterator([4, 5, 6])
494        print(iterator.union(other))
495        # <Iterator([1, 2, 3, 4, 5, 6])>
496        ```
497
498        Parameters
499        ----------
500        other: `Iterator[Item]`
501            The iterable to union with.
502
503        Raises
504        ------
505        `StopIteration`
506            If no elements are left in the iterator.
507        """
508        return Iterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
iterator = Iterator([1, 2, 3])
other = Iterator([4, 5, 6])
print(iterator.union(other))
# <Iterator([1, 2, 3, 4, 5, 6])>
Parameters
  • other (Iterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
510    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
511        """Calls the function on each item in the iterator.
512
513        Example
514        -------
515        ```py
516        iterator = Iterator([1, 2, 3])
517        iterator.for_each(lambda item: print(item))
518        # 1
519        # 2
520        # 3
521        ```
522
523        Parameters
524        ----------
525        func: `typeshed.Callable[[Item], None]`
526            The function to call on each item in the iterator.
527        """
528        for item in self:
529            func(item)

Calls the function on each item in the iterator.

Example
iterator = Iterator([1, 2, 3])
iterator.for_each(lambda item: print(item))
# 1
# 2
# 3
Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
async def async_for_each( self, func: collections.abc.Callable[[~Item], collections.abc.Coroutine[None, None, None]]) -> None:
531    async def async_for_each(
532        self,
533        func: collections.Callable[[Item], collections.Coroutine[None, None, None]],
534    ) -> None:
535        """Calls the async function on each item in the iterator concurrently.
536
537        Example
538        -------
539        ```py
540        async def signup(username: str) -> None:
541            async with aiohttp.request('POST', '...') as r:
542                # Actual logic.
543                ...
544
545        async def main():
546            users = aiobungie.into_iter(["user_danny", "user_jojo"])
547            await users.async_for_each(lambda username: signup(username))
548        ```
549
550        Parameters
551        ----------
552        func: `collections.Callable[[Item], collections.Coroutine[None, None, None]]`
553            The async function to call on each item in the iterator.
554        """
555        await _helpers.awaits(*(func(item) for item in self))

Calls the async function on each item in the iterator concurrently.

Example
async def signup(username: str) -> None:
    async with aiohttp.request('POST', '...') as r:
        # Actual logic.
        ...

async def main():
    users = aiobungie.into_iter(["user_danny", "user_jojo"])
    await users.async_for_each(lambda username: signup(username))
Parameters
  • func (collections.Callable[[Item], collections.Coroutine[None, None, None]]): The async function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> Iterator[tuple[int, ~Item]]:
557    def enumerate(self, *, start: int = 0) -> Iterator[tuple[int, Item]]:
558        """Returns a new iterator that yields tuples of the index and item.
559
560        Example
561        -------
562        ```py
563        iterator = Iterator([1, 2, 3])
564        for index, item in iterator.enumerate():
565            print(index, item)
566        # 0 1
567        # 1 2
568        # 2 3
569        ```
570
571        Raises
572        ------
573        `StopIteration`
574            If no elements are left in the iterator.
575        """
576        return Iterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
iterator = Iterator([1, 2, 3])
for index, item in iterator.enumerate():
    print(index, item)
# 0 1
# 1 2
# 2 3
Raises
  • StopIteration: If no elements are left in the iterator.
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
702@typing.final
703class MembershipOption(int, Enum):
704    """A enum for GroupV2 membership options."""
705
706    REVIEWD = 0
707    OPEN = 1
708    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
450@typing.final
451class MembershipType(int, Enum):
452    """An Enum for Bungie membership types."""
453
454    NONE = 0
455    XBOX = 1
456    PSN = 2
457    STEAM = 3
458    BLIZZARD = 4
459    STADIA = 5
460    EPIC_GAMES_STORE = 6
461    DEMON = 10
462    BUNGIE = 254
463    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
EPIC_GAMES_STORE = <MembershipType.EPIC_GAMES_STORE: 6>
DEMON = <MembershipType.DEMON: 10>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
181@attrs.define(auto_exc=True)
182class MembershipTypeError(BadRequest):
183    """A bad request error raised when passing wrong membership to the request.
184
185    Those fields are useful since it returns the correct membership and id which can be used
186    to make the request again with those fields.
187
188    Example
189    -------
190    ```py
191    try:
192        profile = await client.fetch_profile(
193            member_id=1,
194            type=aiobungie.MembershipType.STADIA,
195            components=()
196        )
197
198    # Membership type is wrong!
199    except aiobungie.MembershipTypeError as err:
200        correct_membership = err.into_membership()
201        profile_id = err.membership_id
202
203        # Recall the method.
204        profile = await client.fetch_profile(
205            member_id=profile_id,
206            type=correct_membership,
207            components=()
208        )
209    ```
210    """
211
212    membership_type: str
213    """The errored membership type passed to the request."""
214
215    membership_id: int
216    """The errored user's membership id."""
217
218    required_membership: str
219    """The required correct membership for errored user."""
220
221    def into_membership(self, value: str | None = None) -> enums.MembershipType:
222        """Turn the required membership from `str` into `aiobungie.Membership` type.
223
224        If value parameter is not provided it will fall back to the required membership.
225        """
226        if value is None:
227            return _MEMBERSHIP_LOOKUP[self.required_membership]
228        return _MEMBERSHIP_LOOKUP[value]
229
230    def __str__(self) -> str:
231        return (
232            f"Expected membership: {self.into_membership().name.replace('_', '').title()}, "
233            f"But got {self.into_membership(self.membership_type)} for id {self.membership_id}"
234        )
235
236    def __int__(self) -> int:
237        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

Example
try:
    profile = await client.fetch_profile(
        member_id=1,
        type=aiobungie.MembershipType.STADIA,
        components=()
    )

# Membership type is wrong!
except aiobungie.MembershipTypeError as err:
    correct_membership = err.into_membership()
    profile_id = err.membership_id

    # Recall the method.
    profile = await client.fetch_profile(
        member_id=profile_id,
        type=correct_membership,
        components=()
    )
MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], membership_type: str, membership_id: int, required_membership: str)
 2def __init__(self, message, url, body, headers, membership_type, membership_id, required_membership):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = attr_dict['http_status'].default
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

def into_membership( self, value: str | None = None) -> MembershipType:
221    def into_membership(self, value: str | None = None) -> enums.MembershipType:
222        """Turn the required membership from `str` into `aiobungie.Membership` type.
223
224        If value parameter is not provided it will fall back to the required membership.
225        """
226        if value is None:
227            return _MEMBERSHIP_LOOKUP[self.required_membership]
228        return _MEMBERSHIP_LOOKUP[value]

Turn the required membership from str into aiobungie.Membership type.

If value parameter is not provided it will fall back to the required membership.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
add_note
args
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
495@typing.final
496class MilestoneType(int, Enum):
497    """An Enum for Destiny 2 milestone types."""
498
499    UNKNOWN = 0
500    TUTORIAL = 1
501    ONETIME = 2
502    WEEKLY = 3
503    DAILY = 4
504    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
145@attrs.define(auto_exc=True)
146class NotFound(HTTPException):
147    """Raised when an unknown resource was not found."""
148
149    http_status: http.HTTPStatus = attrs.field(
150        default=http.HTTPStatus.NOT_FOUND, init=False
151    )

Raised when an unknown resource was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 93@typing.final
 94class ObjectiveUIStyle(int, enums.Enum):
 95    NONE = 0
 96    HIGHLIGHTED = 1
 97    CRAFTING_WEAPON_LEVEL = 2
 98    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
 99    CRAFTING_WEAPON_TIMESTAMP = 4
100    CRAFTING_MEMENTOS = 5
101    CRAFTING_MEMENTO_TITLE = 6

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.

>>> int('0b100', base=0)
4
NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
219@typing.final
220class Place(int, Enum):
221    """An Enum for Destiny 2 Places and NOT Planets"""
222
223    ORBIT = 2961497387
224    SOCIAL = 4151112093
225    LIGHT_HOUSE = 4276116472
226    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
184@typing.final
185class Planet(int, Enum):
186    """An Enum for all available planets in Destiny 2."""
187
188    UNKNOWN = 0
189    """Unknown space"""
190
191    EARTH = 3747705955
192    """Earth"""
193
194    DREAMING_CITY = 2877881518
195    """The Dreaming city."""
196
197    NESSUS = 3526908984
198    """Nessus"""
199
200    MOON = 3325508439
201    """The Moon"""
202
203    COSMODROME = 3990611421
204    """The Cosmodrome"""
205
206    TANGLED_SHORE = 3821439926
207    """The Tangled Shore"""
208
209    VENUS = 3871070152
210    """Venus"""
211
212    EAZ = 541863059  # Exclusive event.
213    """European Aerial Zone"""
214
215    EUROPA = 1729879943
216    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
672@typing.final
673class Presence(int, Enum):
674    """An enum for a bungie friend status."""
675
676    OFFLINE_OR_UNKNOWN = 0
677    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
760@typing.final
761class PrivacySetting(int, Enum):
762    """An enum for players's privacy settings."""
763
764    OPEN = 0
765    CLAN_AND_FRIENDS = 1
766    FRIENDS_ONLY = 2
767    INVITE_ONLY = 3
768    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 311class RESTClient(interfaces.RESTInterface):
 312    """A single process REST client implementation.
 313
 314    This client is designed to only make HTTP requests and return raw JSON objects.
 315
 316    Example
 317    -------
 318    ```py
 319    import aiobungie
 320
 321    client = aiobungie.RESTClient("TOKEN")
 322    async with client:
 323        response = await client.fetch_clan_members(4389205)
 324        for member in response['results']:
 325            print(member['destinyUserInfo'])
 326    ```
 327
 328    Parameters
 329    ----------
 330    token : `str`
 331        A valid application token from Bungie's developer portal.
 332
 333    Other Parameters
 334    ----------------
 335    max_retries : `int`
 336        The max retries number to retry if the request hit a `5xx` status code.
 337    client_secret : `str | None`
 338        An optional application client secret,
 339        This is only needed if you're fetching OAuth2 tokens with this client.
 340    client_id : `int | None`
 341        An optional application client id,
 342        This is only needed if you're fetching OAuth2 tokens with this client.
 343    debug : `bool | str`
 344        Whether to enable logging responses or not.
 345
 346    Logging Levels
 347    --------------
 348    * `False`: This will disable logging.
 349    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 350    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 351    """
 352
 353    __slots__ = (
 354        "_token",
 355        "_session",
 356        "_lock",
 357        "_max_retries",
 358        "_client_secret",
 359        "_client_id",
 360        "_metadata",
 361        "_dumps",
 362        "_loads",
 363    )
 364
 365    def __init__(
 366        self,
 367        token: str,
 368        /,
 369        *,
 370        client_secret: str | None = None,
 371        client_id: int | None = None,
 372        client_session: aiohttp.ClientSession | None = None,
 373        dumps: typedefs.Dumps = helpers.dumps,
 374        loads: typedefs.Loads = helpers.loads,
 375        max_retries: int = 4,
 376        debug: typing.Literal["TRACE"] | bool | int = False,
 377    ) -> None:
 378        self._session = client_session
 379        self._lock: asyncio.Lock | None = None
 380        self._client_secret = client_secret
 381        self._client_id = client_id
 382        self._token: str = token
 383        self._max_retries = max_retries
 384        self._dumps = dumps
 385        self._loads = loads
 386        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 387        self.with_debug(debug)
 388
 389    @property
 390    def client_id(self) -> int | None:
 391        return self._client_id
 392
 393    @property
 394    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 395        return self._metadata
 396
 397    @property
 398    def is_alive(self) -> bool:
 399        return self._session is not None
 400
 401    @typing.final
 402    async def close(self) -> None:
 403        if self._session is None:
 404            raise RuntimeError("REST client is not running.")
 405
 406        await self._session.close()
 407        self._session = None
 408
 409    @typing.final
 410    def open(self) -> None:
 411        """Open a new client session. This is called internally with contextmanager usage."""
 412        if self._session:
 413            raise RuntimeError("Cannot open REST client when it's already open.")
 414
 415        self._session = aiohttp.ClientSession(
 416            connector=aiohttp.TCPConnector(),
 417            connector_owner=True,
 418            raise_for_status=False,
 419            timeout=aiohttp.ClientTimeout(total=30.0),
 420        )
 421
 422    @typing.final
 423    async def static_request(
 424        self,
 425        method: _HTTP_METHOD,
 426        path: str,
 427        *,
 428        auth: str | None = None,
 429        json: collections.Mapping[str, typing.Any] | None = None,
 430    ) -> typedefs.JSONIsh:
 431        return await self._request(method, path, auth=auth, json=json)
 432
 433    @typing.overload
 434    def build_oauth2_url(self, client_id: int) -> builders.OAuthURL:
 435        ...
 436
 437    @typing.overload
 438    def build_oauth2_url(self) -> builders.OAuthURL | None:
 439        ...
 440
 441    @typing.final
 442    def build_oauth2_url(
 443        self, client_id: int | None = None
 444    ) -> builders.OAuthURL | None:
 445        client_id = client_id or self._client_id
 446        if client_id is None:
 447            return None
 448
 449        return builders.OAuthURL(client_id=client_id)
 450
 451    @typing.final
 452    def with_debug(
 453        self,
 454        level: typing.Literal["TRACE"] | bool | int = True,
 455        file: str | pathlib.Path | None = None,
 456    ) -> None:
 457        """Enable debugging for this client with a level. Defaults to `True`.
 458
 459        Parameters
 460        ----------
 461        level: `NotRequired[int | bool | typing.Literal["TRACE"] | None]`
 462            The level of the logger. This field is not required.
 463        file: `pathlib.Path | str | None`
 464            An optional file to write the logs into.
 465
 466        Logging Levels
 467        --------------
 468        * `False`: This will disable logging.
 469        * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 470        * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 471        """
 472        logging.logThreads = False
 473        logging.logMultiprocessing = False
 474        logging.logProcesses = False
 475        logging.captureWarnings(True)
 476
 477        format = "%(levelname)s " "%(asctime)23.23s " "%(name)s: " "%(message)s"
 478
 479        file_handler = (logging.FileHandler(file),) if file else None
 480        if level == "TRACE" or level == TRACE:
 481            logging.basicConfig(
 482                level=TRACE, format=format, stream=sys.stdout, handlers=file_handler
 483            )
 484
 485        elif level is True:
 486            logging.basicConfig(
 487                level=logging.DEBUG,
 488                format=format,
 489                stream=sys.stdout,
 490                handlers=file_handler,
 491            )
 492
 493    async def _request(
 494        self,
 495        method: _HTTP_METHOD,
 496        route: str,
 497        *,
 498        base: bool = False,
 499        oauth2: bool = False,
 500        auth: str | None = None,
 501        unwrap_bytes: bool = False,
 502        json: collections.Mapping[str, typing.Any] | None = None,
 503        data: collections.Mapping[str, typing.Any] | None = None,
 504        params: collections.Mapping[str, typing.Any] | None = None,
 505    ) -> typedefs.JSONIsh:
 506        # This is not None when opening the client.
 507        assert self._session is not None
 508
 509        retries: int = 0
 510        headers: collections.MutableMapping[str, typing.Any] = {}
 511
 512        headers[_USER_AGENT_HEADERS] = _USER_AGENT
 513        headers["X-API-KEY"] = self._token
 514
 515        if auth is not None:
 516            headers[_AUTH_HEADER] = f"Bearer {auth}"
 517
 518        # Handling endpoints
 519        endpoint = url.BASE
 520
 521        if not base:
 522            endpoint = endpoint + url.REST_EP
 523
 524        if oauth2:
 525            assert self._client_id
 526            assert self._client_secret
 527            headers["client_secret"] = self._client_secret
 528
 529            headers["Content-Type"] = "application/x-www-form-urlencoded"
 530            endpoint = endpoint + url.TOKEN_EP
 531
 532        if self._lock is None:
 533            self._lock = asyncio.Lock()
 534
 535        if json:
 536            headers["Content-Type"] = _APP_JSON
 537
 538        stack = contextlib.AsyncExitStack()
 539        while True:
 540            try:
 541                await stack.enter_async_context(self._lock)
 542
 543                # We make the request here.
 544                taken_time = time.monotonic()
 545                response = await self._session.request(
 546                    method=method,
 547                    url=f"{endpoint}/{route}",
 548                    headers=headers,
 549                    data=_JSONPayload(json) if json else data,
 550                    params=params,
 551                )
 552                response_time = (time.monotonic() - taken_time) * 1_000
 553
 554                _LOGGER.debug(
 555                    "%s %s %s Time %.4fms",
 556                    method,
 557                    f"{endpoint}/{route}",
 558                    f"{response.status} {response.reason}",
 559                    response_time,
 560                )
 561
 562                await self._handle_ratelimit(response, method, route)
 563
 564            except aiohttp.ClientConnectionError as exc:
 565                if retries >= self._max_retries:
 566                    raise error.HTTPError(
 567                        str(exc),
 568                        http.HTTPStatus.SERVICE_UNAVAILABLE,
 569                    )
 570                backoff_ = backoff.ExponentialBackOff(maximum=8)
 571
 572                timer = next(backoff_)
 573                _LOGGER.warning(
 574                    "Client received a connection error <%s> Retrying in %.2fs. Remaining retries: %s",
 575                    type(exc).__qualname__,
 576                    timer,
 577                    self._max_retries - retries,
 578                )
 579                retries += 1
 580                await asyncio.sleep(timer)
 581                continue
 582
 583            finally:
 584                await stack.aclose()
 585
 586            if response.status == http.HTTPStatus.NO_CONTENT:
 587                return None
 588
 589            # Handle the successful response.
 590            if 300 > response.status >= 200:
 591                if unwrap_bytes:
 592                    # We need to read the bytes for the manifest response.
 593                    return await response.read()
 594
 595                # Bungie get funky and return HTML instead of JSON when making an authorized
 596                # request with a dummy access token. We could technically read the page content
 597                # but that's Bungie's fault for not returning a JSON response.
 598                if response.content_type != _APP_JSON:
 599                    raise error.HTTPError(
 600                        message=f"Expected JSON response, Got {response.content_type}, "
 601                        f"{response.real_url.human_repr()}",
 602                        http_status=http.HTTPStatus(response.status),
 603                    )
 604
 605                json_data = self._loads(await response.read())
 606
 607                _LOGGER.debug(
 608                    "%s %s %s Time %.4fms",
 609                    method,
 610                    f"{endpoint}/{route}",
 611                    f"{response.status} {response.reason}",
 612                    response_time,
 613                )
 614
 615                if _LOGGER.isEnabledFor(TRACE):
 616                    _LOGGER.log(
 617                        TRACE,
 618                        "%s",
 619                        error.stringify_headers(dict(response.headers)),
 620                    )
 621
 622                    details: collections.MutableMapping[str, typing.Any] = {}
 623                    if json:
 624                        details["json"] = json
 625
 626                    if data:
 627                        details["data"] = data
 628
 629                    if params:
 630                        details["params"] = params
 631
 632                    if details:
 633                        _LOGGER.log(TRACE, "%s", error.stringify_headers(details))
 634
 635                # Return the response.
 636                # auth responses are not inside a Response object.
 637                if oauth2:
 638                    return json_data
 639
 640                # The reason we have a type ignore is because the actual response type
 641                # is within this `Response` key.
 642                return json_data["Response"]  # type: ignore
 643
 644            if (
 645                response.status in _RETRY_5XX and retries < self._max_retries  # noqa: W503
 646            ):
 647                backoff_ = backoff.ExponentialBackOff(maximum=6)
 648                sleep_time = next(backoff_)
 649                _LOGGER.warning(
 650                    "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 651                    response.status,
 652                    response.reason,
 653                    sleep_time,
 654                    self._max_retries - retries,
 655                )
 656
 657                retries += 1
 658                await asyncio.sleep(sleep_time)
 659                continue
 660
 661            raise await error.panic(response)
 662
 663    async def __aenter__(self) -> RESTClient:
 664        self.open()
 665        return self
 666
 667    async def __aexit__(
 668        self,
 669        exception_type: type[BaseException] | None,
 670        exception: BaseException | None,
 671        exception_traceback: types.TracebackType | None,
 672    ) -> None:
 673        await self.close()
 674
 675    # We don't want this to be super complicated.
 676    @typing.final
 677    async def _handle_ratelimit(
 678        self,
 679        response: aiohttp.ClientResponse,
 680        method: str,
 681        route: str,
 682    ) -> None:
 683        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 684            return
 685
 686        if response.content_type != _APP_JSON:
 687            raise error.HTTPError(
 688                f"Being ratelimited on non JSON request, {response.content_type}.",
 689                http.HTTPStatus.TOO_MANY_REQUESTS,
 690            )
 691
 692        # The reason we have a type ignore here is that we guaranteed the content type is JSON above.
 693        json: typedefs.JSONObject = self._loads(await response.read())  # type: ignore
 694        retry_after = float(json.get("ThrottleSeconds", 15.0)) + 0.1
 695        max_calls: int = 0
 696
 697        while True:
 698            if max_calls == 10:
 699                # Max retries by default. We raise an error here.
 700                raise error.RateLimitedError(
 701                    body=json,
 702                    url=str(response.real_url),
 703                    retry_after=retry_after,
 704                )
 705
 706            # We sleep for a little bit to avoid funky behavior.
 707            _LOGGER.warning(
 708                "We're being ratelimited, Method %s Route %s. Sleeping for %.2fs.",
 709                method,
 710                route,
 711                retry_after,
 712            )
 713            await asyncio.sleep(retry_after)
 714            max_calls += 1
 715            continue
 716
 717    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 718        data = {
 719            "grant_type": "authorization_code",
 720            "code": code,
 721            "client_id": self._client_id,
 722            "client_secret": self._client_secret,
 723        }
 724
 725        response = await self._request(_POST, "", data=data, oauth2=True)
 726        assert isinstance(response, dict)
 727        return builders.OAuth2Response.build_response(response)
 728
 729    async def refresh_access_token(
 730        self, refresh_token: str, /
 731    ) -> builders.OAuth2Response:
 732        data = {
 733            "grant_type": "refresh_token",
 734            "refresh_token": refresh_token,
 735            "client_id": self._client_id,
 736            "client_secret": self._client_secret,
 737        }
 738
 739        response = await self._request(_POST, "", data=data, oauth2=True)
 740        assert isinstance(response, dict)
 741        return builders.OAuth2Response.build_response(response)
 742
 743    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 744        resp = await self._request(_GET, f"User/GetBungieNetUserById/{id}/")
 745        assert isinstance(resp, dict)
 746        return resp
 747
 748    async def fetch_user_themes(self) -> typedefs.JSONArray:
 749        resp = await self._request(_GET, "User/GetAvailableThemes/")
 750        assert isinstance(resp, list)
 751        return resp
 752
 753    async def fetch_membership_from_id(
 754        self,
 755        id: int,
 756        type: enums.MembershipType | int = enums.MembershipType.NONE,
 757        /,
 758    ) -> typedefs.JSONObject:
 759        resp = await self._request(_GET, f"User/GetMembershipsById/{id}/{int(type)}")
 760        assert isinstance(resp, dict)
 761        return resp
 762
 763    async def fetch_membership(
 764        self,
 765        name: str,
 766        code: int,
 767        type: enums.MembershipType | int = enums.MembershipType.ALL,
 768        /,
 769    ) -> typedefs.JSONArray:
 770        resp = await self._request(
 771            _POST,
 772            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 773            json={"displayName": name, "displayNameCode": code},
 774        )
 775        assert isinstance(resp, list)
 776        return resp
 777
 778    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 779        resp = await self._request(
 780            _POST,
 781            "User/Search/GlobalName/0",
 782            json={"displayNamePrefix": name},
 783        )
 784        assert isinstance(resp, dict)
 785        return resp
 786
 787    async def fetch_clan_from_id(
 788        self, id: int, /, access_token: str | None = None
 789    ) -> typedefs.JSONObject:
 790        resp = await self._request(_GET, f"GroupV2/{id}", auth=access_token)
 791        assert isinstance(resp, dict)
 792        return resp
 793
 794    async def fetch_clan(
 795        self,
 796        name: str,
 797        /,
 798        access_token: str | None = None,
 799        *,
 800        type: enums.GroupType | int = enums.GroupType.CLAN,
 801    ) -> typedefs.JSONObject:
 802        resp = await self._request(
 803            _GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 804        )
 805        assert isinstance(resp, dict)
 806        return resp
 807
 808    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 809        resp = await self._request(_GET, f"GroupV2/{clan_id}/AdminsAndFounder/")
 810        assert isinstance(resp, dict)
 811        return resp
 812
 813    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 814        resp = await self._request(_GET, f"GroupV2/{clan_id}/OptionalConversations/")
 815        assert isinstance(resp, list)
 816        return resp
 817
 818    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 819        resp = await self._request(_GET, f"App/Application/{appid}")
 820        assert isinstance(resp, dict)
 821        return resp
 822
 823    async def fetch_character(
 824        self,
 825        member_id: int,
 826        membership_type: enums.MembershipType | int,
 827        character_id: int,
 828        components: collections.Sequence[enums.ComponentType],
 829        auth: str | None = None,
 830    ) -> typedefs.JSONObject:
 831        collector = _collect_components(components)
 832        response = await self._request(
 833            _GET,
 834            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 835            f"Character/{character_id}/?components={collector}",
 836            auth=auth,
 837        )
 838        assert isinstance(response, dict)
 839        return response
 840
 841    async def fetch_activities(
 842        self,
 843        member_id: int,
 844        character_id: int,
 845        mode: enums.GameMode | int,
 846        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
 847        *,
 848        page: int = 0,
 849        limit: int = 1,
 850    ) -> typedefs.JSONObject:
 851        resp = await self._request(
 852            _GET,
 853            f"Destiny2/{int(membership_type)}/Account/"
 854            f"{member_id}/Character/{character_id}/Stats/Activities"
 855            f"/?mode={int(mode)}&count={limit}&page={page}",
 856        )
 857        assert isinstance(resp, dict)
 858        return resp
 859
 860    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 861        resp = await self._request(
 862            _GET,
 863            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 864        )
 865        assert isinstance(resp, dict)
 866        return resp
 867
 868    async def fetch_profile(
 869        self,
 870        membership_id: int,
 871        type: enums.MembershipType | int,
 872        components: collections.Sequence[enums.ComponentType],
 873        auth: str | None = None,
 874    ) -> typedefs.JSONObject:
 875        collector = _collect_components(components)
 876        response = await self._request(
 877            _GET,
 878            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 879            auth=auth,
 880        )
 881        assert isinstance(response, dict)
 882        return response
 883
 884    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 885        response = await self._request(_GET, route=f"Destiny2/Manifest/{type}/{hash}")
 886        assert isinstance(response, dict)
 887        return response
 888
 889    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 890        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 891        assert isinstance(resp, dict)
 892        return resp
 893
 894    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 895        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 896        assert isinstance(resp, dict)
 897        return resp
 898
 899    async def fetch_groups_for_member(
 900        self,
 901        member_id: int,
 902        member_type: enums.MembershipType | int,
 903        /,
 904        *,
 905        filter: int = 0,
 906        group_type: enums.GroupType | int = enums.GroupType.CLAN,
 907    ) -> typedefs.JSONObject:
 908        resp = await self._request(
 909            _GET,
 910            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 911        )
 912        assert isinstance(resp, dict)
 913        return resp
 914
 915    async def fetch_potential_groups_for_member(
 916        self,
 917        member_id: int,
 918        member_type: enums.MembershipType | int,
 919        /,
 920        *,
 921        filter: int = 0,
 922        group_type: enums.GroupType | int = enums.GroupType.CLAN,
 923    ) -> typedefs.JSONObject:
 924        resp = await self._request(
 925            _GET,
 926            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 927        )
 928        assert isinstance(resp, dict)
 929        return resp
 930
 931    async def fetch_clan_members(
 932        self,
 933        clan_id: int,
 934        /,
 935        *,
 936        name: str | None = None,
 937        type: enums.MembershipType | int = enums.MembershipType.NONE,
 938    ) -> typedefs.JSONObject:
 939        resp = await self._request(
 940            _GET,
 941            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 942        )
 943        assert isinstance(resp, dict)
 944        return resp
 945
 946    async def fetch_hardlinked_credentials(
 947        self,
 948        credential: int,
 949        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
 950        /,
 951    ) -> typedefs.JSONObject:
 952        resp = await self._request(
 953            _GET,
 954            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
 955        )
 956        assert isinstance(resp, dict)
 957        return resp
 958
 959    async def fetch_user_credentials(
 960        self, access_token: str, membership_id: int, /
 961    ) -> typedefs.JSONArray:
 962        resp = await self._request(
 963            _GET,
 964            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
 965            auth=access_token,
 966        )
 967        assert isinstance(resp, list)
 968        return resp
 969
 970    async def insert_socket_plug(
 971        self,
 972        action_token: str,
 973        /,
 974        instance_id: int,
 975        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
 976        character_id: int,
 977        membership_type: enums.MembershipType | int,
 978    ) -> typedefs.JSONObject:
 979        if isinstance(plug, builders.PlugSocketBuilder):
 980            plug = plug.collect()
 981
 982        body = {
 983            "actionToken": action_token,
 984            "itemInstanceId": instance_id,
 985            "plug": plug,
 986            "characterId": character_id,
 987            "membershipType": int(membership_type),
 988        }
 989        resp = await self._request(
 990            _POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
 991        )
 992        assert isinstance(resp, dict)
 993        return resp
 994
 995    async def insert_socket_plug_free(
 996        self,
 997        access_token: str,
 998        /,
 999        instance_id: int,
1000        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
1001        character_id: int,
1002        membership_type: enums.MembershipType | int,
1003    ) -> typedefs.JSONObject:
1004        if isinstance(plug, builders.PlugSocketBuilder):
1005            plug = plug.collect()
1006
1007        body = {
1008            "itemInstanceId": instance_id,
1009            "plug": plug,
1010            "characterId": character_id,
1011            "membershipType": int(membership_type),
1012        }
1013        resp = await self._request(
1014            _POST,
1015            "Destiny2/Actions/Items/InsertSocketPlugFree",
1016            json=body,
1017            auth=access_token,
1018        )
1019        assert isinstance(resp, dict)
1020        return resp
1021
1022    @helpers.unstable
1023    async def set_item_lock_state(
1024        self,
1025        access_token: str,
1026        state: bool,
1027        /,
1028        item_id: int,
1029        character_id: int,
1030        membership_type: enums.MembershipType | int,
1031    ) -> int:
1032        body = {
1033            "state": state,
1034            "itemId": item_id,
1035            "characterId": character_id,
1036            "membershipType": int(membership_type),
1037        }
1038        response = await self._request(
1039            _POST,
1040            "Destiny2/Actions/Items/SetLockState",
1041            json=body,
1042            auth=access_token,
1043        )
1044        assert isinstance(response, int)
1045        return response
1046
1047    async def set_quest_track_state(
1048        self,
1049        access_token: str,
1050        state: bool,
1051        /,
1052        item_id: int,
1053        character_id: int,
1054        membership_type: enums.MembershipType | int,
1055    ) -> int:
1056        body = {
1057            "state": state,
1058            "itemId": item_id,
1059            "characterId": character_id,
1060            "membership_type": int(membership_type),
1061        }
1062        response = await self._request(
1063            _POST,
1064            "Destiny2/Actions/Items/SetTrackedState",
1065            json=body,
1066            auth=access_token,
1067        )
1068        assert isinstance(response, int)
1069        return response
1070
1071    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1072        path = await self._request(_GET, "Destiny2/Manifest")
1073        assert isinstance(path, dict)
1074        return path
1075
1076    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1077        _ensure_manifest_language(language)
1078
1079        content = await self.fetch_manifest_path()
1080        resp = await self._request(
1081            _GET,
1082            content["mobileWorldContentPaths"][language],
1083            unwrap_bytes=True,
1084            base=True,
1085        )
1086        assert isinstance(resp, bytes)
1087        return resp
1088
1089    async def download_sqlite_manifest(
1090        self,
1091        language: str = "en",
1092        name: str = "manifest",
1093        path: pathlib.Path | str = ".",
1094        *,
1095        force: bool = False,
1096        executor: concurrent.futures.Executor | None = None,
1097    ) -> pathlib.Path:
1098        complete_path = _get_path(name, path, sql=True)
1099
1100        if complete_path.exists() and force:
1101            if force:
1102                _LOGGER.info(
1103                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1104                )
1105                complete_path.unlink(missing_ok=True)
1106
1107                return await self.download_sqlite_manifest(
1108                    language, name, path, force=force
1109                )
1110
1111            else:
1112                raise FileExistsError(
1113                    "Manifest file already exists, "
1114                    "To force download, set the `force` parameter to `True`."
1115                )
1116
1117        _LOGGER.info(f"Downloading manifest. Location: {complete_path!s}")
1118        data_bytes = await self.read_manifest_bytes(language)
1119        await asyncio.get_running_loop().run_in_executor(
1120            executor, _write_sqlite_bytes, data_bytes, path, name
1121        )
1122        _LOGGER.info("Finished downloading manifest.")
1123        return _get_path(name, path, sql=True)
1124
1125    async def download_json_manifest(
1126        self,
1127        file_name: str = "manifest",
1128        path: str | pathlib.Path = ".",
1129        *,
1130        language: str = "en",
1131        executor: concurrent.futures.Executor | None = None,
1132    ) -> pathlib.Path:
1133        _ensure_manifest_language(language)
1134        full_path = _get_path(file_name, path)
1135        _LOGGER.info(f"Downloading manifest JSON to {full_path!r}...")
1136
1137        content = await self.fetch_manifest_path()
1138        json_bytes = await self._request(
1139            _GET,
1140            content["jsonWorldContentPaths"][language],
1141            unwrap_bytes=True,
1142            base=True,
1143        )
1144
1145        assert isinstance(json_bytes, bytes)
1146        await asyncio.get_running_loop().run_in_executor(
1147            executor, _write_json_bytes, json_bytes, file_name, path
1148        )
1149        _LOGGER.info("Finished downloading manifest JSON.")
1150        return full_path
1151
1152    async def fetch_manifest_version(self) -> str:
1153        # This is guaranteed str.
1154        return (await self.fetch_manifest_path())["version"]
1155
1156    async def fetch_linked_profiles(
1157        self,
1158        member_id: int,
1159        member_type: enums.MembershipType | int,
1160        /,
1161        *,
1162        all: bool = False,
1163    ) -> typedefs.JSONObject:
1164        resp = await self._request(
1165            _GET,
1166            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1167        )
1168        assert isinstance(resp, dict)
1169        return resp
1170
1171    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1172        resp = await self._request(_GET, "Destiny2/Clan/ClanBannerDictionary/")
1173        assert isinstance(resp, dict)
1174        return resp
1175
1176    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1177        resp = await self._request(_GET, "Destiny2/Milestones/")
1178        assert isinstance(resp, dict)
1179        return resp
1180
1181    async def fetch_public_milestone_content(
1182        self, milestone_hash: int, /
1183    ) -> typedefs.JSONObject:
1184        resp = await self._request(
1185            _GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1186        )
1187        assert isinstance(resp, dict)
1188        return resp
1189
1190    async def fetch_current_user_memberships(
1191        self, access_token: str, /
1192    ) -> typedefs.JSONObject:
1193        resp = await self._request(
1194            _GET,
1195            "User/GetMembershipsForCurrentUser/",
1196            auth=access_token,
1197        )
1198        assert isinstance(resp, dict)
1199        return resp
1200
1201    async def equip_item(
1202        self,
1203        access_token: str,
1204        /,
1205        item_id: int,
1206        character_id: int,
1207        membership_type: enums.MembershipType | int,
1208    ) -> None:
1209        payload = {
1210            "itemId": item_id,
1211            "characterId": character_id,
1212            "membershipType": int(membership_type),
1213        }
1214
1215        await self._request(
1216            _POST,
1217            "Destiny2/Actions/Items/EquipItem/",
1218            json=payload,
1219            auth=access_token,
1220        )
1221
1222    async def equip_items(
1223        self,
1224        access_token: str,
1225        /,
1226        item_ids: collections.Sequence[int],
1227        character_id: int,
1228        membership_type: enums.MembershipType | int,
1229    ) -> None:
1230        payload = {
1231            "itemIds": item_ids,
1232            "characterId": character_id,
1233            "membershipType": int(membership_type),
1234        }
1235        await self._request(
1236            _POST,
1237            "Destiny2/Actions/Items/EquipItems/",
1238            json=payload,
1239            auth=access_token,
1240        )
1241
1242    async def ban_clan_member(
1243        self,
1244        access_token: str,
1245        /,
1246        group_id: int,
1247        membership_id: int,
1248        membership_type: enums.MembershipType | int,
1249        *,
1250        length: int = 0,
1251        comment: str | None = None,
1252    ) -> None:
1253        payload = {"comment": str(comment), "length": length}
1254        await self._request(
1255            _POST,
1256            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1257            json=payload,
1258            auth=access_token,
1259        )
1260
1261    async def unban_clan_member(
1262        self,
1263        access_token: str,
1264        /,
1265        group_id: int,
1266        membership_id: int,
1267        membership_type: enums.MembershipType | int,
1268    ) -> None:
1269        await self._request(
1270            _POST,
1271            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1272            auth=access_token,
1273        )
1274
1275    async def kick_clan_member(
1276        self,
1277        access_token: str,
1278        /,
1279        group_id: int,
1280        membership_id: int,
1281        membership_type: enums.MembershipType | int,
1282    ) -> typedefs.JSONObject:
1283        resp = await self._request(
1284            _POST,
1285            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1286            auth=access_token,
1287        )
1288        assert isinstance(resp, dict)
1289        return resp
1290
1291    async def edit_clan(
1292        self,
1293        access_token: str,
1294        /,
1295        group_id: int,
1296        *,
1297        name: str | None = None,
1298        about: str | None = None,
1299        motto: str | None = None,
1300        theme: str | None = None,
1301        tags: collections.Sequence[str] | None = None,
1302        is_public: bool | None = None,
1303        locale: str | None = None,
1304        avatar_image_index: int | None = None,
1305        membership_option: enums.MembershipOption | int | None = None,
1306        allow_chat: bool | None = None,
1307        chat_security: typing.Literal[0, 1] | None = None,
1308        call_sign: str | None = None,
1309        homepage: typing.Literal[0, 1, 2] | None = None,
1310        enable_invite_messaging_for_admins: bool | None = None,
1311        default_publicity: typing.Literal[0, 1, 2] | None = None,
1312        is_public_topic_admin: bool | None = None,
1313    ) -> None:
1314        payload = {
1315            "name": name,
1316            "about": about,
1317            "motto": motto,
1318            "theme": theme,
1319            "tags": tags,
1320            "isPublic": is_public,
1321            "avatarImageIndex": avatar_image_index,
1322            "isPublicTopicAdminOnly": is_public_topic_admin,
1323            "allowChat": allow_chat,
1324            "chatSecurity": chat_security,
1325            "callsign": call_sign,
1326            "homepage": homepage,
1327            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1328            "defaultPublicity": default_publicity,
1329            "locale": locale,
1330        }
1331        if membership_option is not None:
1332            payload["membershipOption"] = int(membership_option)
1333
1334        await self._request(
1335            _POST,
1336            f"GroupV2/{group_id}/Edit",
1337            json=payload,
1338            auth=access_token,
1339        )
1340
1341    async def edit_clan_options(
1342        self,
1343        access_token: str,
1344        /,
1345        group_id: int,
1346        *,
1347        invite_permissions_override: bool | None = None,
1348        update_culture_permissionOverride: bool | None = None,
1349        host_guided_game_permission_override: typing.Literal[0, 1, 2] | None = None,
1350        update_banner_permission_override: bool | None = None,
1351        join_level: enums.ClanMemberType | int | None = None,
1352    ) -> None:
1353        payload = {
1354            "InvitePermissionOverride": invite_permissions_override,
1355            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1356            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1357            "UpdateBannerPermissionOverride": update_banner_permission_override,
1358            "JoinLevel": int(join_level) if join_level else None,
1359        }
1360
1361        await self._request(
1362            _POST,
1363            f"GroupV2/{group_id}/EditFounderOptions",
1364            json=payload,
1365            auth=access_token,
1366        )
1367
1368    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1369        resp = await self._request(
1370            _GET,
1371            "Social/Friends/",
1372            auth=access_token,
1373        )
1374        assert isinstance(resp, dict)
1375        return resp
1376
1377    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1378        resp = await self._request(
1379            _GET,
1380            "Social/Friends/Requests",
1381            auth=access_token,
1382        )
1383        assert isinstance(resp, dict)
1384        return resp
1385
1386    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1387        await self._request(
1388            _POST,
1389            f"Social/Friends/Requests/Accept/{member_id}",
1390            auth=access_token,
1391        )
1392
1393    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1394        await self._request(
1395            _POST,
1396            f"Social/Friends/Add/{member_id}",
1397            auth=access_token,
1398        )
1399
1400    async def decline_friend_request(
1401        self, access_token: str, /, member_id: int
1402    ) -> None:
1403        await self._request(
1404            _POST,
1405            f"Social/Friends/Requests/Decline/{member_id}",
1406            auth=access_token,
1407        )
1408
1409    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1410        await self._request(
1411            _POST,
1412            f"Social/Friends/Remove/{member_id}",
1413            auth=access_token,
1414        )
1415
1416    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1417        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1418        await self._request(
1419            _POST,
1420            f"Social/Friends/Requests/Remove/{member_id}",
1421            auth=access_token,
1422        )
1423
1424    async def approve_all_pending_group_users(
1425        self,
1426        access_token: str,
1427        /,
1428        group_id: int,
1429        message: str | None = None,
1430    ) -> None:
1431        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1432        await self._request(
1433            _POST,
1434            f"GroupV2/{group_id}/Members/ApproveAll",
1435            auth=access_token,
1436            json={"message": str(message)},
1437        )
1438
1439    async def deny_all_pending_group_users(
1440        self,
1441        access_token: str,
1442        /,
1443        group_id: int,
1444        *,
1445        message: str | None = None,
1446    ) -> None:
1447        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1448        await self._request(
1449            _POST,
1450            f"GroupV2/{group_id}/Members/DenyAll",
1451            auth=access_token,
1452            json={"message": str(message)},
1453        )
1454
1455    async def add_optional_conversation(
1456        self,
1457        access_token: str,
1458        /,
1459        group_id: int,
1460        *,
1461        name: str | None = None,
1462        security: typing.Literal[0, 1] = 0,
1463    ) -> None:
1464        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1465        payload = {"chatName": str(name), "chatSecurity": security}
1466        await self._request(
1467            _POST,
1468            f"GroupV2/{group_id}/OptionalConversations/Add",
1469            json=payload,
1470            auth=access_token,
1471        )
1472
1473    async def edit_optional_conversation(
1474        self,
1475        access_token: str,
1476        /,
1477        group_id: int,
1478        conversation_id: int,
1479        *,
1480        name: str | None = None,
1481        security: typing.Literal[0, 1] = 0,
1482        enable_chat: bool = False,
1483    ) -> None:
1484        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1485        payload = {
1486            "chatEnabled": enable_chat,
1487            "chatName": str(name),
1488            "chatSecurity": security,
1489        }
1490        await self._request(
1491            _POST,
1492            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1493            json=payload,
1494            auth=access_token,
1495        )
1496
1497    async def transfer_item(
1498        self,
1499        access_token: str,
1500        /,
1501        item_id: int,
1502        item_hash: int,
1503        character_id: int,
1504        member_type: enums.MembershipType | int,
1505        *,
1506        stack_size: int = 1,
1507        vault: bool = False,
1508    ) -> None:
1509        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1510        payload = {
1511            "characterId": character_id,
1512            "membershipType": int(member_type),
1513            "itemId": item_id,
1514            "itemReferenceHash": item_hash,
1515            "stackSize": stack_size,
1516            "transferToVault": vault,
1517        }
1518        await self._request(
1519            _POST,
1520            "Destiny2/Actions/Items/TransferItem",
1521            json=payload,
1522            auth=access_token,
1523        )
1524
1525    async def pull_item(
1526        self,
1527        access_token: str,
1528        /,
1529        item_id: int,
1530        item_hash: int,
1531        character_id: int,
1532        member_type: enums.MembershipType | int,
1533        *,
1534        stack_size: int = 1,
1535        vault: bool = False,
1536    ) -> None:
1537        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1538        payload = {
1539            "characterId": character_id,
1540            "membershipType": int(member_type),
1541            "itemId": item_id,
1542            "itemReferenceHash": item_hash,
1543            "stackSize": stack_size,
1544            "transferToVault": vault,
1545        }
1546        await self._request(
1547            _POST,
1548            "Destiny2/Actions/Items/PullFromPostmaster",
1549            json=payload,
1550            auth=access_token,
1551        )
1552
1553    async def fetch_fireteams(
1554        self,
1555        activity_type: fireteams.FireteamActivity | int,
1556        *,
1557        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
1558        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
1559        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1560        page: int = 0,
1561        slots_filter: int = 0,
1562    ) -> typedefs.JSONObject:
1563        resp = await self._request(
1564            _GET,
1565            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1566        )
1567        assert isinstance(resp, dict)
1568        return resp
1569
1570    async def fetch_available_clan_fireteams(
1571        self,
1572        access_token: str,
1573        group_id: int,
1574        activity_type: fireteams.FireteamActivity | int,
1575        *,
1576        platform: fireteams.FireteamPlatform | int,
1577        language: fireteams.FireteamLanguage | str,
1578        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1579        page: int = 0,
1580        public_only: bool = False,
1581        slots_filter: int = 0,
1582    ) -> typedefs.JSONObject:
1583        resp = await self._request(
1584            _GET,
1585            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1586            json={"langFilter": str(language)},
1587            auth=access_token,
1588        )
1589        assert isinstance(resp, dict)
1590        return resp
1591
1592    async def fetch_clan_fireteam(
1593        self, access_token: str, fireteam_id: int, group_id: int
1594    ) -> typedefs.JSONObject:
1595        resp = await self._request(
1596            _GET,
1597            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1598            auth=access_token,
1599        )
1600        assert isinstance(resp, dict)
1601        return resp
1602
1603    async def fetch_my_clan_fireteams(
1604        self,
1605        access_token: str,
1606        group_id: int,
1607        *,
1608        include_closed: bool = True,
1609        platform: fireteams.FireteamPlatform | int,
1610        language: fireteams.FireteamLanguage | str,
1611        filtered: bool = True,
1612        page: int = 0,
1613    ) -> typedefs.JSONObject:
1614        payload = {"groupFilter": filtered, "langFilter": str(language)}
1615
1616        resp = await self._request(
1617            _GET,
1618            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1619            json=payload,
1620            auth=access_token,
1621        )
1622        assert isinstance(resp, dict)
1623        return resp
1624
1625    async def fetch_private_clan_fireteams(
1626        self, access_token: str, group_id: int, /
1627    ) -> int:
1628        resp = await self._request(
1629            _GET,
1630            f"Fireteam/Clan/{group_id}/ActiveCount",
1631            auth=access_token,
1632        )
1633        assert isinstance(resp, int)
1634        return resp
1635
1636    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1637        resp = await self._request(
1638            _GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1639        )
1640        assert isinstance(resp, dict)
1641        return resp
1642
1643    async def search_entities(
1644        self, name: str, entity_type: str, *, page: int = 0
1645    ) -> typedefs.JSONObject:
1646        resp = await self._request(
1647            _GET,
1648            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1649            json={"page": page},
1650        )
1651        assert isinstance(resp, dict)
1652        return resp
1653
1654    async def fetch_unique_weapon_history(
1655        self,
1656        membership_id: int,
1657        character_id: int,
1658        membership_type: enums.MembershipType | int,
1659    ) -> typedefs.JSONObject:
1660        resp = await self._request(
1661            _GET,
1662            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1663        )
1664        assert isinstance(resp, dict)
1665        return resp
1666
1667    async def fetch_item(
1668        self,
1669        member_id: int,
1670        item_id: int,
1671        membership_type: enums.MembershipType | int,
1672        components: collections.Sequence[enums.ComponentType],
1673    ) -> typedefs.JSONObject:
1674        collector = _collect_components(components)
1675
1676        resp = await self._request(
1677            _GET,
1678            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1679        )
1680        assert isinstance(resp, dict)
1681        return resp
1682
1683    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1684        resp = await self._request(_GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/")
1685        assert isinstance(resp, dict)
1686        return resp
1687
1688    async def fetch_available_locales(self) -> typedefs.JSONObject:
1689        resp = await self._request(_GET, "Destiny2/Manifest/DestinyLocaleDefinition/")
1690        assert isinstance(resp, dict)
1691        return resp
1692
1693    async def fetch_common_settings(self) -> typedefs.JSONObject:
1694        resp = await self._request(_GET, "Settings")
1695        assert isinstance(resp, dict)
1696        return resp
1697
1698    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1699        resp = await self._request(_GET, "UserSystemOverrides")
1700        assert isinstance(resp, dict)
1701        return resp
1702
1703    async def fetch_global_alerts(
1704        self, *, include_streaming: bool = False
1705    ) -> typedefs.JSONArray:
1706        resp = await self._request(
1707            _GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1708        )
1709        assert isinstance(resp, list)
1710        return resp
1711
1712    async def awainitialize_request(
1713        self,
1714        access_token: str,
1715        type: typing.Literal[0, 1],
1716        membership_type: enums.MembershipType | int,
1717        /,
1718        *,
1719        affected_item_id: int | None = None,
1720        character_id: int | None = None,
1721    ) -> typedefs.JSONObject:
1722        body = {"type": type, "membershipType": int(membership_type)}
1723
1724        if affected_item_id is not None:
1725            body["affectedItemId"] = affected_item_id
1726
1727        if character_id is not None:
1728            body["characterId"] = character_id
1729
1730        resp = await self._request(
1731            _POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1732        )
1733        assert isinstance(resp, dict)
1734        return resp
1735
1736    async def awaget_action_token(
1737        self, access_token: str, correlation_id: str, /
1738    ) -> typedefs.JSONObject:
1739        resp = await self._request(
1740            _POST,
1741            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1742            auth=access_token,
1743        )
1744        assert isinstance(resp, dict)
1745        return resp
1746
1747    async def awa_provide_authorization_result(
1748        self,
1749        access_token: str,
1750        selection: int,
1751        correlation_id: str,
1752        nonce: collections.MutableSequence[str | bytes],
1753    ) -> int:
1754        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1755
1756        resp = await self._request(
1757            _POST,
1758            "Destiny2/Awa/AwaProvideAuthorizationResult",
1759            json=body,
1760            auth=access_token,
1761        )
1762        assert isinstance(resp, int)
1763        return resp
1764
1765    async def fetch_vendors(
1766        self,
1767        access_token: str,
1768        character_id: int,
1769        membership_id: int,
1770        membership_type: enums.MembershipType | int,
1771        /,
1772        components: collections.Sequence[enums.ComponentType],
1773        filter: int | None = None,
1774    ) -> typedefs.JSONObject:
1775        components_ = _collect_components(components)
1776        route = (
1777            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1778            f"/Character/{character_id}/Vendors/?components={components_}"
1779        )
1780
1781        if filter is not None:
1782            route = route + f"&filter={filter}"
1783
1784        resp = await self._request(
1785            _GET,
1786            route,
1787            auth=access_token,
1788        )
1789        assert isinstance(resp, dict)
1790        return resp
1791
1792    async def fetch_vendor(
1793        self,
1794        access_token: str,
1795        character_id: int,
1796        membership_id: int,
1797        membership_type: enums.MembershipType | int,
1798        vendor_hash: int,
1799        /,
1800        components: collections.Sequence[enums.ComponentType],
1801    ) -> typedefs.JSONObject:
1802        components_ = _collect_components(components)
1803        resp = await self._request(
1804            _GET,
1805            (
1806                f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1807                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1808            ),
1809            auth=access_token,
1810        )
1811        assert isinstance(resp, dict)
1812        return resp
1813
1814    async def fetch_application_api_usage(
1815        self,
1816        access_token: str,
1817        application_id: int,
1818        /,
1819        *,
1820        start: datetime.datetime | None = None,
1821        end: datetime.datetime | None = None,
1822    ) -> typedefs.JSONObject:
1823        end_date, start_date = time.parse_date_range(end, start)
1824        resp = await self._request(
1825            _GET,
1826            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1827            auth=access_token,
1828        )
1829        assert isinstance(resp, dict)
1830        return resp
1831
1832    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1833        resp = await self._request(_GET, "App/FirstParty")
1834        assert isinstance(resp, list)
1835        return resp
1836
1837    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1838        resp = await self._request(_GET, f"Content/GetContentType/{type}/")
1839        assert isinstance(resp, dict)
1840        return resp
1841
1842    async def fetch_content_by_id(
1843        self, id: int, locale: str, /, *, head: bool = False
1844    ) -> typedefs.JSONObject:
1845        resp = await self._request(
1846            _GET,
1847            f"Content/GetContentById/{id}/{locale}/",
1848            json={"head": head},
1849        )
1850        assert isinstance(resp, dict)
1851        return resp
1852
1853    async def fetch_content_by_tag_and_type(
1854        self, locale: str, tag: str, type: str, *, head: bool = False
1855    ) -> typedefs.JSONObject:
1856        resp = await self._request(
1857            _GET,
1858            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1859            json={"head": head},
1860        )
1861        assert isinstance(resp, dict)
1862        return resp
1863
1864    async def search_content_with_text(
1865        self,
1866        locale: str,
1867        /,
1868        content_type: str,
1869        search_text: str,
1870        tag: str,
1871        *,
1872        page: int | None = None,
1873        source: str | None = None,
1874    ) -> typedefs.JSONObject:
1875        body: typedefs.JSONObject = {
1876            "locale": locale,
1877            "currentpage": page or 1,
1878            "ctype": content_type,
1879            "searchtxt": search_text,
1880            "searchtext": search_text,
1881            "tag": tag,
1882            "source": source,
1883        }
1884
1885        resp = await self._request(_GET, "Content/Search", params=body)
1886        assert isinstance(resp, dict)
1887        return resp
1888
1889    async def search_content_by_tag_and_type(
1890        self,
1891        locale: str,
1892        tag: str,
1893        type: str,
1894        *,
1895        page: int | None = None,
1896    ) -> typedefs.JSONObject:
1897        body: typedefs.JSONObject = {"currentpage": page or 1}
1898
1899        resp = await self._request(
1900            _GET,
1901            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1902            params=body,
1903        )
1904        assert isinstance(resp, dict)
1905        return resp
1906
1907    async def search_help_articles(
1908        self, text: str, size: str, /
1909    ) -> typedefs.JSONObject:
1910        resp = await self._request(_GET, f"Content/SearchHelpArticles/{text}/{size}/")
1911        assert isinstance(resp, dict)
1912        return resp
1913
1914    async def fetch_topics_page(
1915        self,
1916        category_filter: int,
1917        group: int,
1918        date_filter: int,
1919        sort: str | bytes,
1920        *,
1921        page: int | None = None,
1922        locales: collections.Iterable[str] | None = None,
1923        tag_filter: str | None = None,
1924    ) -> typedefs.JSONObject:
1925        params = {
1926            "locales": ",".join(locales) if locales is not None else "en",
1927        }
1928        if tag_filter:
1929            params["tagstring"] = tag_filter
1930
1931        resp = await self._request(
1932            _GET,
1933            f"Forum/GetTopicsPaged/{page or 0}/0/{group}/{sort!s}/{date_filter}/{category_filter}/",
1934            params=params,
1935        )
1936        assert isinstance(resp, dict)
1937        return resp
1938
1939    async def fetch_core_topics_page(
1940        self,
1941        category_filter: int,
1942        date_filter: int,
1943        sort: str | bytes,
1944        *,
1945        page: int | None = None,
1946        locales: collections.Iterable[str] | None = None,
1947    ) -> typedefs.JSONObject:
1948        resp = await self._request(
1949            _GET,
1950            f"Forum/GetCoreTopicsPaged/{page or 0}"
1951            f"/{sort!s}/{date_filter}/{category_filter}/?locales={','.join(locales) if locales else 'en'}",
1952        )
1953        assert isinstance(resp, dict)
1954        return resp
1955
1956    async def fetch_posts_threaded_page(
1957        self,
1958        parent_post: bool,
1959        page: int,
1960        page_size: int,
1961        parent_post_id: int,
1962        reply_size: int,
1963        root_thread_mode: bool,
1964        sort_mode: int,
1965        show_banned: str | None = None,
1966    ) -> typedefs.JSONObject:
1967        resp = await self._request(
1968            _GET,
1969            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
1970            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
1971            json={"showbanned": show_banned},
1972        )
1973        assert isinstance(resp, dict)
1974        return resp
1975
1976    async def fetch_posts_threaded_page_from_child(
1977        self,
1978        child_id: bool,
1979        page: int,
1980        page_size: int,
1981        reply_size: int,
1982        root_thread_mode: bool,
1983        sort_mode: int,
1984        show_banned: str | None = None,
1985    ) -> typedefs.JSONObject:
1986        resp = await self._request(
1987            _GET,
1988            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
1989            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
1990            json={"showbanned": show_banned},
1991        )
1992        assert isinstance(resp, dict)
1993        return resp
1994
1995    async def fetch_post_and_parent(
1996        self, child_id: int, /, *, show_banned: str | None = None
1997    ) -> typedefs.JSONObject:
1998        resp = await self._request(
1999            _GET,
2000            f"Forum/GetPostAndParent/{child_id}/",
2001            json={"showbanned": show_banned},
2002        )
2003        assert isinstance(resp, dict)
2004        return resp
2005
2006    async def fetch_posts_and_parent_awaiting(
2007        self, child_id: int, /, *, show_banned: str | None = None
2008    ) -> typedefs.JSONObject:
2009        resp = await self._request(
2010            _GET,
2011            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2012            json={"showbanned": show_banned},
2013        )
2014        assert isinstance(resp, dict)
2015        return resp
2016
2017    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2018        resp = await self._request(_GET, f"Forum/GetTopicForContent/{content_id}/")
2019        assert isinstance(resp, int)
2020        return resp
2021
2022    async def fetch_forum_tag_suggestions(
2023        self, partial_tag: str, /
2024    ) -> typedefs.JSONObject:
2025        resp = await self._request(
2026            _GET,
2027            "Forum/GetForumTagSuggestions/",
2028            json={"partialtag": partial_tag},
2029        )
2030        assert isinstance(resp, dict)
2031        return resp
2032
2033    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2034        resp = await self._request(_GET, f"Forum/Poll/{topic_id}/")
2035        assert isinstance(resp, dict)
2036        return resp
2037
2038    async def fetch_recruitment_thread_summaries(self) -> typedefs.JSONArray:
2039        resp = await self._request(_POST, "Forum/Recruit/Summaries/")
2040        assert isinstance(resp, list)
2041        return resp
2042
2043    async def fetch_recommended_groups(
2044        self,
2045        access_token: str,
2046        /,
2047        *,
2048        date_range: int = 0,
2049        group_type: enums.GroupType | int = enums.GroupType.CLAN,
2050    ) -> typedefs.JSONArray:
2051        resp = await self._request(
2052            _POST,
2053            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2054            auth=access_token,
2055        )
2056        assert isinstance(resp, list)
2057        return resp
2058
2059    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2060        resp = await self._request(_GET, "GroupV2/GetAvailableAvatars/")
2061        assert isinstance(resp, dict)
2062        return resp
2063
2064    async def fetch_user_clan_invite_setting(
2065        self,
2066        access_token: str,
2067        /,
2068        membership_type: enums.MembershipType | int,
2069    ) -> bool:
2070        resp = await self._request(
2071            _GET,
2072            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2073            auth=access_token,
2074        )
2075        assert isinstance(resp, bool)
2076        return resp
2077
2078    async def fetch_banned_group_members(
2079        self, access_token: str, group_id: int, /, *, page: int = 1
2080    ) -> typedefs.JSONObject:
2081        resp = await self._request(
2082            _GET,
2083            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2084            auth=access_token,
2085        )
2086        assert isinstance(resp, dict)
2087        return resp
2088
2089    async def fetch_pending_group_memberships(
2090        self, access_token: str, group_id: int, /, *, current_page: int = 1
2091    ) -> typedefs.JSONObject:
2092        resp = await self._request(
2093            _GET,
2094            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2095            auth=access_token,
2096        )
2097        assert isinstance(resp, dict)
2098        return resp
2099
2100    async def fetch_invited_group_memberships(
2101        self, access_token: str, group_id: int, /, *, current_page: int = 1
2102    ) -> typedefs.JSONObject:
2103        resp = await self._request(
2104            _GET,
2105            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2106            auth=access_token,
2107        )
2108        assert isinstance(resp, dict)
2109        return resp
2110
2111    async def invite_member_to_group(
2112        self,
2113        access_token: str,
2114        /,
2115        group_id: int,
2116        membership_id: int,
2117        membership_type: enums.MembershipType | int,
2118        *,
2119        message: str | None = None,
2120    ) -> typedefs.JSONObject:
2121        resp = await self._request(
2122            _POST,
2123            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2124            auth=access_token,
2125            json={"message": str(message)},
2126        )
2127        assert isinstance(resp, dict)
2128        return resp
2129
2130    async def cancel_group_member_invite(
2131        self,
2132        access_token: str,
2133        /,
2134        group_id: int,
2135        membership_id: int,
2136        membership_type: enums.MembershipType | int,
2137    ) -> typedefs.JSONObject:
2138        resp = await self._request(
2139            _POST,
2140            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2141            auth=access_token,
2142        )
2143        assert isinstance(resp, dict)
2144        return resp
2145
2146    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2147        resp = await self._request(_GET, "Destiny2/Stats/Definition/")
2148        assert isinstance(resp, dict)
2149        return resp
2150
2151    async def fetch_historical_stats(
2152        self,
2153        character_id: int,
2154        membership_id: int,
2155        membership_type: enums.MembershipType | int,
2156        day_start: datetime.datetime,
2157        day_end: datetime.datetime,
2158        groups: collections.Sequence[enums.StatsGroupType | int],
2159        modes: collections.Sequence[enums.GameMode | int],
2160        *,
2161        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2162    ) -> typedefs.JSONObject:
2163        end, start = time.parse_date_range(day_end, day_start)
2164        resp = await self._request(
2165            _GET,
2166            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2167            json={
2168                "dayend": end,
2169                "daystart": start,
2170                "groups": [str(int(group)) for group in groups],
2171                "modes": [str(int(mode)) for mode in modes],
2172                "periodType": int(period_type),
2173            },
2174        )
2175        assert isinstance(resp, dict)
2176        return resp
2177
2178    async def fetch_historical_stats_for_account(
2179        self,
2180        membership_id: int,
2181        membership_type: enums.MembershipType | int,
2182        groups: collections.Sequence[enums.StatsGroupType | int],
2183    ) -> typedefs.JSONObject:
2184        resp = await self._request(
2185            _GET,
2186            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2187            json={"groups": [str(int(group)) for group in groups]},
2188        )
2189        assert isinstance(resp, dict)
2190        return resp
2191
2192    async def fetch_aggregated_activity_stats(
2193        self,
2194        character_id: int,
2195        membership_id: int,
2196        membership_type: enums.MembershipType | int,
2197        /,
2198    ) -> typedefs.JSONObject:
2199        resp = await self._request(
2200            _GET,
2201            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2202            f"Character/{character_id}/Stats/AggregateActivityStats/",
2203        )
2204        assert isinstance(resp, dict)
2205        return resp
2206
2207    async def equip_loadout(
2208        self,
2209        access_token: str,
2210        /,
2211        loadout_index: int,
2212        character_id: int,
2213        membership_type: enums.MembershipType | int,
2214    ) -> None:
2215        response = await self._request(
2216            _POST,
2217            "Destiny2/Actions/Loadouts/EquipLoadout/",
2218            json={
2219                "loadoutIndex": loadout_index,
2220                "characterId": character_id,
2221                "membership_type": int(membership_type),
2222            },
2223            auth=access_token,
2224        )
2225        assert isinstance(response, int)
2226
2227    async def snapshot_loadout(
2228        self,
2229        access_token: str,
2230        /,
2231        loadout_index: int,
2232        character_id: int,
2233        membership_type: enums.MembershipType | int,
2234        *,
2235        color_hash: int | None = None,
2236        icon_hash: int | None = None,
2237        name_hash: int | None = None,
2238    ) -> None:
2239        response = await self._request(
2240            _POST,
2241            "Destiny2/Actions/Loadouts/SnapshotLoadout/",
2242            auth=access_token,
2243            json={
2244                "colorHash": color_hash,
2245                "iconHash": icon_hash,
2246                "nameHash": name_hash,
2247                "loadoutIndex": loadout_index,
2248                "characterId": character_id,
2249                "membershipType": int(membership_type),
2250            },
2251        )
2252        assert isinstance(response, int)
2253
2254    async def update_loadout(
2255        self,
2256        access_token: str,
2257        /,
2258        loadout_index: int,
2259        character_id: int,
2260        membership_type: enums.MembershipType | int,
2261        *,
2262        color_hash: int | None = None,
2263        icon_hash: int | None = None,
2264        name_hash: int | None = None,
2265    ) -> None:
2266        response = await self._request(
2267            _POST,
2268            "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/",
2269            auth=access_token,
2270            json={
2271                "colorHash": color_hash,
2272                "iconHash": icon_hash,
2273                "nameHash": name_hash,
2274                "loadoutIndex": loadout_index,
2275                "characterId": character_id,
2276                "membershipType": int(membership_type),
2277            },
2278        )
2279        assert isinstance(response, int)
2280
2281    async def clear_loadout(
2282        self,
2283        access_token: str,
2284        /,
2285        loadout_index: int,
2286        character_id: int,
2287        membership_type: enums.MembershipType | int,
2288    ) -> None:
2289        response = await self._request(
2290            _POST,
2291            "Destiny2/Actions/Loadouts/ClearLoadout/",
2292            json={
2293                "loadoutIndex": loadout_index,
2294                "characterId": character_id,
2295                "membership_type": int(membership_type),
2296            },
2297            auth=access_token,
2298        )
2299        assert isinstance(response, int)

A single process REST client implementation.

This client is designed to only make HTTP requests and return raw JSON objects.

Example
import aiobungie

client = aiobungie.RESTClient("TOKEN")
async with client:
    response = await client.fetch_clan_members(4389205)
    for member in response['results']:
        print(member['destinyUserInfo'])
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • debug (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, *, client_secret: str | None = None, client_id: int | None = None, client_session: aiohttp.client.ClientSession | None = None, dumps: collections.abc.Callable[[collections.abc.Mapping[str, typing.Any] | collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]], bytes] = <function dumps>, loads: collections.abc.Callable[[str | bytes], collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] | collections.abc.Mapping[str, typing.Any]] = <function loads>, max_retries: int = 4, debug: Union[Literal['TRACE'], bool, int] = False)
365    def __init__(
366        self,
367        token: str,
368        /,
369        *,
370        client_secret: str | None = None,
371        client_id: int | None = None,
372        client_session: aiohttp.ClientSession | None = None,
373        dumps: typedefs.Dumps = helpers.dumps,
374        loads: typedefs.Loads = helpers.loads,
375        max_retries: int = 4,
376        debug: typing.Literal["TRACE"] | bool | int = False,
377    ) -> None:
378        self._session = client_session
379        self._lock: asyncio.Lock | None = None
380        self._client_secret = client_secret
381        self._client_id = client_id
382        self._token: str = token
383        self._max_retries = max_retries
384        self._dumps = dumps
385        self._loads = loads
386        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
387        self.with_debug(debug)
client_id: int | None
389    @property
390    def client_id(self) -> int | None:
391        return self._client_id

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]
393    @property
394    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
395        return self._metadata

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool
397    @property
398    def is_alive(self) -> bool:
399        return self._session is not None

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
401    @typing.final
402    async def close(self) -> None:
403        if self._session is None:
404            raise RuntimeError("REST client is not running.")
405
406        await self._session.close()
407        self._session = None

Close this REST client session if it was acquired.

This method is automatically called when using async with contextmanager.

Raises
  • RuntimeError: If the client is already closed.
@typing.final
def open(self) -> None:
409    @typing.final
410    def open(self) -> None:
411        """Open a new client session. This is called internally with contextmanager usage."""
412        if self._session:
413            raise RuntimeError("Cannot open REST client when it's already open.")
414
415        self._session = aiohttp.ClientSession(
416            connector=aiohttp.TCPConnector(),
417            connector_owner=True,
418            raise_for_status=False,
419            timeout=aiohttp.ClientTimeout(total=30.0),
420        )

Open a new client session. This is called internally with contextmanager usage.

@typing.final
async def static_request( self, method: Literal['GET', 'DELETE', 'POST', 'PUT', 'PATCH'], path: str, *, auth: str | None = None, json: collections.abc.Mapping[str, typing.Any] | None = None) -> collections.abc.Mapping[str, typing.Any] | collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] | bytes | str | int | bool | None:
422    @typing.final
423    async def static_request(
424        self,
425        method: _HTTP_METHOD,
426        path: str,
427        *,
428        auth: str | None = None,
429        json: collections.Mapping[str, typing.Any] | None = None,
430    ) -> typedefs.JSONIsh:
431        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
Other Parameters
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (MutableMapping[str, typing.Any] | None): An optional JSON mapping to include in the request.
Returns
  • aiobungie.typedefs.JSONIsh: The response payload.
@typing.final
def build_oauth2_url(self, client_id: int | None = None) -> aiobungie.builders.OAuthURL | None:
441    @typing.final
442    def build_oauth2_url(
443        self, client_id: int | None = None
444    ) -> builders.OAuthURL | None:
445        client_id = client_id or self._client_id
446        if client_id is None:
447            return None
448
449        return builders.OAuthURL(client_id=client_id)

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

You can't get the complete string URL by using .compile() method.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
@typing.final
def with_debug( self, level: Union[Literal['TRACE'], bool, int] = True, file: str | pathlib.Path | None = None) -> None:
451    @typing.final
452    def with_debug(
453        self,
454        level: typing.Literal["TRACE"] | bool | int = True,
455        file: str | pathlib.Path | None = None,
456    ) -> None:
457        """Enable debugging for this client with a level. Defaults to `True`.
458
459        Parameters
460        ----------
461        level: `NotRequired[int | bool | typing.Literal["TRACE"] | None]`
462            The level of the logger. This field is not required.
463        file: `pathlib.Path | str | None`
464            An optional file to write the logs into.
465
466        Logging Levels
467        --------------
468        * `False`: This will disable logging.
469        * `True`: This will set the level to `DEBUG` and enable logging minimal information.
470        * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
471        """
472        logging.logThreads = False
473        logging.logMultiprocessing = False
474        logging.logProcesses = False
475        logging.captureWarnings(True)
476
477        format = "%(levelname)s " "%(asctime)23.23s " "%(name)s: " "%(message)s"
478
479        file_handler = (logging.FileHandler(file),) if file else None
480        if level == "TRACE" or level == TRACE:
481            logging.basicConfig(
482                level=TRACE, format=format, stream=sys.stdout, handlers=file_handler
483            )
484
485        elif level is True:
486            logging.basicConfig(
487                level=logging.DEBUG,
488                format=format,
489                stream=sys.stdout,
490                handlers=file_handler,
491            )

Enable debugging for this client with a level. Defaults to True.

Parameters
  • level (NotRequired[int | bool | typing.Literal["TRACE"] | None]): The level of the logger. This field is not required.
  • file (pathlib.Path | str | None): An optional file to write the logs into.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
717    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
718        data = {
719            "grant_type": "authorization_code",
720            "code": code,
721            "client_id": self._client_id,
722            "client_secret": self._client_secret,
723        }
724
725        response = await self._request(_POST, "", data=data, oauth2=True)
726        assert isinstance(response, dict)
727        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
729    async def refresh_access_token(
730        self, refresh_token: str, /
731    ) -> builders.OAuth2Response:
732        data = {
733            "grant_type": "refresh_token",
734            "refresh_token": refresh_token,
735            "client_id": self._client_id,
736            "client_secret": self._client_secret,
737        }
738
739        response = await self._request(_POST, "", data=data, oauth2=True)
740        assert isinstance(response, dict)
741        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> collections.abc.Mapping[str, typing.Any]:
743    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
744        resp = await self._request(_GET, f"User/GetBungieNetUserById/{id}/")
745        assert isinstance(resp, dict)
746        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes( self) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
748    async def fetch_user_themes(self) -> typedefs.JSONArray:
749        resp = await self._request(_GET, "User/GetAvailableThemes/")
750        assert isinstance(resp, list)
751        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: MembershipType | int = <MembershipType.NONE: 0>, /) -> collections.abc.Mapping[str, typing.Any]:
753    async def fetch_membership_from_id(
754        self,
755        id: int,
756        type: enums.MembershipType | int = enums.MembershipType.NONE,
757        /,
758    ) -> typedefs.JSONObject:
759        resp = await self._request(_GET, f"User/GetMembershipsById/{id}/{int(type)}")
760        assert isinstance(resp, dict)
761        return resp

Fetch Bungie user's memberships from their id.

Parameters
  • id (int): The user's id.
  • type (aiobungie.aiobungie.MembershipType | int): The user's membership type.
Returns
Raises
async def fetch_membership( self, name: str, code: int, type: MembershipType | int = <MembershipType.ALL: -1>, /) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
763    async def fetch_membership(
764        self,
765        name: str,
766        code: int,
767        type: enums.MembershipType | int = enums.MembershipType.ALL,
768        /,
769    ) -> typedefs.JSONArray:
770        resp = await self._request(
771            _POST,
772            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
773            json={"displayName": name, "displayNameCode": code},
774        )
775        assert isinstance(resp, list)
776        return resp

Fetch a Destiny 2 Player.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.aiobungie.MembershipType | int): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def search_users(self, name: str, /) -> collections.abc.Mapping[str, typing.Any]:
778    async def search_users(self, name: str, /) -> typedefs.JSONObject:
779        resp = await self._request(
780            _POST,
781            "User/Search/GlobalName/0",
782            json={"displayNamePrefix": name},
783        )
784        assert isinstance(resp, dict)
785        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
787    async def fetch_clan_from_id(
788        self, id: int, /, access_token: str | None = None
789    ) -> typedefs.JSONObject:
790        resp = await self._request(_GET, f"GroupV2/{id}", auth=access_token)
791        assert isinstance(resp, dict)
792        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (str | None): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: str | None = None, *, type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Mapping[str, typing.Any]:
794    async def fetch_clan(
795        self,
796        name: str,
797        /,
798        access_token: str | None = None,
799        *,
800        type: enums.GroupType | int = enums.GroupType.CLAN,
801    ) -> typedefs.JSONObject:
802        resp = await self._request(
803            _GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
804        )
805        assert isinstance(resp, dict)
806        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
  • access_token (str | None): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

  • type (aiobungie.aiobungie.GroupType | int): The group type, Default is one.
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
808    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
809        resp = await self._request(_GET, f"GroupV2/{clan_id}/AdminsAndFounder/")
810        assert isinstance(resp, dict)
811        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
813    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
814        resp = await self._request(_GET, f"GroupV2/{clan_id}/OptionalConversations/")
815        assert isinstance(resp, list)
816        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> collections.abc.Mapping[str, typing.Any]:
818    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
819        resp = await self._request(_GET, f"App/Application/{appid}")
820        assert isinstance(resp, dict)
821        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: MembershipType | int, character_id: int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
823    async def fetch_character(
824        self,
825        member_id: int,
826        membership_type: enums.MembershipType | int,
827        character_id: int,
828        components: collections.Sequence[enums.ComponentType],
829        auth: str | None = None,
830    ) -> typedefs.JSONObject:
831        collector = _collect_components(components)
832        response = await self._request(
833            _GET,
834            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
835            f"Character/{character_id}/?components={collector}",
836            auth=auth,
837        )
838        assert isinstance(response, dict)
839        return response

Fetch a Destiny 2 player's characters.

Parameters
  • member_id (int): A valid bungie member id.
  • membership_type (aiobungie.aiobungie.internal.enums.MembershipType | int): The member's membership type.
  • character_id (int): The character id to return.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of character components to collect and return.
Other Parameters
  • auth (str | None): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: GameMode | int, membership_type: MembershipType | int = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> collections.abc.Mapping[str, typing.Any]:
841    async def fetch_activities(
842        self,
843        member_id: int,
844        character_id: int,
845        mode: enums.GameMode | int,
846        membership_type: enums.MembershipType | int = enums.MembershipType.ALL,
847        *,
848        page: int = 0,
849        limit: int = 1,
850    ) -> typedefs.JSONObject:
851        resp = await self._request(
852            _GET,
853            f"Destiny2/{int(membership_type)}/Account/"
854            f"{member_id}/Character/{character_id}/Stats/Activities"
855            f"/?mode={int(mode)}&count={limit}&page={page}",
856        )
857        assert isinstance(resp, dict)
858        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.aiobungie.GameMode | int): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.aiobungie.internal.enums.MembershipType | int): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default to 1
  • limit (int): Limit the returned result. Default to 1
Returns
Raises
async def fetch_vendor_sales(self) -> collections.abc.Mapping[str, typing.Any]:
860    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
861        resp = await self._request(
862            _GET,
863            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
864        )
865        assert isinstance(resp, dict)
866        return resp
async def fetch_profile( self, membership_id: int, type: MembershipType | int, components: collections.abc.Sequence[ComponentType], auth: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
868    async def fetch_profile(
869        self,
870        membership_id: int,
871        type: enums.MembershipType | int,
872        components: collections.Sequence[enums.ComponentType],
873        auth: str | None = None,
874    ) -> typedefs.JSONObject:
875        collector = _collect_components(components)
876        response = await self._request(
877            _GET,
878            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
879            auth=auth,
880        )
881        assert isinstance(response, dict)
882        return response

Fetch a bungie profile.

Parameters
  • membership_id (int): The member's id.
  • type (aiobungie.aiobungie.MembershipType | int): A valid membership type.
  • components (collections.Sequence[aiobungie.ComponentType]): A sequence of profile components to collect and return.
Other Parameters
  • auth (str | None): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> collections.abc.Mapping[str, typing.Any]:
884    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
885        response = await self._request(_GET, route=f"Destiny2/Manifest/{type}/{hash}")
886        assert isinstance(response, dict)
887        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> collections.abc.Mapping[str, typing.Any]:
889    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
890        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
891        assert isinstance(resp, dict)
892        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> collections.abc.Mapping[str, typing.Any]:
894    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
895        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
896        assert isinstance(resp, dict)
897        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Mapping[str, typing.Any]:
899    async def fetch_groups_for_member(
900        self,
901        member_id: int,
902        member_type: enums.MembershipType | int,
903        /,
904        *,
905        filter: int = 0,
906        group_type: enums.GroupType | int = enums.GroupType.CLAN,
907    ) -> typedefs.JSONObject:
908        resp = await self._request(
909            _GET,
910            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
911        )
912        assert isinstance(resp, dict)
913        return resp

Fetch the information about the groups for a member.

Parameters
  • member_id (int): The member's id
  • member_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • filter (int): Filter apply to list of joined groups. This Default to 0
  • group_type (aiobungie.aiobungie.GroupType | int): The group's type. This is always set to aiobungie.GroupType.CLAN and should not be changed.
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: MembershipType | int, /, *, filter: int = 0, group_type: GroupType | int = <GroupType.CLAN: 1>) -> collections.abc.Mapping[str, typing.Any]:
915    async def fetch_potential_groups_for_member(
916        self,
917        member_id: int,
918        member_type: enums.MembershipType | int,
919        /,
920        *,
921        filter: int = 0,
922        group_type: enums.GroupType | int = enums.GroupType.CLAN,
923    ) -> typedefs.JSONObject:
924        resp = await self._request(
925            _GET,
926            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
927        )
928        assert isinstance(resp, dict)
929        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
  • member_id (int): The member's id
  • member_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • filter (int): Filter apply to list of joined groups. This Default to 0
  • group_type (aiobungie.aiobungie.GroupType | int): The group's type. This is always set to aiobungie.GroupType.CLAN and should not be changed.
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: str | None = None, type: MembershipType | int = <MembershipType.NONE: 0>) -> collections.abc.Mapping[str, typing.Any]:
931    async def fetch_clan_members(
932        self,
933        clan_id: int,
934        /,
935        *,
936        name: str | None = None,
937        type: enums.MembershipType | int = enums.MembershipType.NONE,
938    ) -> typedefs.JSONObject:
939        resp = await self._request(
940            _GET,
941            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
942        )
943        assert isinstance(resp, dict)
944        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (str | None): If provided, Only players matching this name will be returned.
  • type (aiobungie.aiobungie.MembershipType | int): An optional clan member's membership type. Default is set to aiobungie.MembershipType.NONE Which returns the first matched clan member by their name.
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: CredentialType | int = <CredentialType.STEAMID: 12>, /) -> collections.abc.Mapping[str, typing.Any]:
946    async def fetch_hardlinked_credentials(
947        self,
948        credential: int,
949        type: enums.CredentialType | int = enums.CredentialType.STEAMID,
950        /,
951    ) -> typedefs.JSONObject:
952        resp = await self._request(
953            _GET,
954            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
955        )
956        assert isinstance(resp, dict)
957        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.aiobungie.CredentialType | int): The credential type. This must not be changed Since its only credential that works "currently"
Returns
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
959    async def fetch_user_credentials(
960        self, access_token: str, membership_id: int, /
961    ) -> typedefs.JSONArray:
962        resp = await self._request(
963            _GET,
964            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
965            auth=access_token,
966        )
967        assert isinstance(resp, list)
968        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: aiobungie.builders.PlugSocketBuilder | collections.abc.Mapping[str, int], character_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
970    async def insert_socket_plug(
971        self,
972        action_token: str,
973        /,
974        instance_id: int,
975        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
976        character_id: int,
977        membership_type: enums.MembershipType | int,
978    ) -> typedefs.JSONObject:
979        if isinstance(plug, builders.PlugSocketBuilder):
980            plug = plug.collect()
981
982        body = {
983            "actionToken": action_token,
984            "itemInstanceId": instance_id,
985            "plug": plug,
986            "characterId": character_id,
987            "membershipType": int(membership_type),
988        }
989        resp = await self._request(
990            _POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
991        )
992        assert isinstance(resp, dict)
993        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (aiobungie.builders.PlugSocketBuilder | Mapping[str, int]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.aiobungie.MembershipType | int The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: aiobungie.builders.PlugSocketBuilder | collections.abc.Mapping[str, int], character_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
 995    async def insert_socket_plug_free(
 996        self,
 997        access_token: str,
 998        /,
 999        instance_id: int,
1000        plug: builders.PlugSocketBuilder | collections.Mapping[str, int],
1001        character_id: int,
1002        membership_type: enums.MembershipType | int,
1003    ) -> typedefs.JSONObject:
1004        if isinstance(plug, builders.PlugSocketBuilder):
1005            plug = plug.collect()
1006
1007        body = {
1008            "itemInstanceId": instance_id,
1009            "plug": plug,
1010            "characterId": character_id,
1011            "membershipType": int(membership_type),
1012        }
1013        resp = await self._request(
1014            _POST,
1015            "Destiny2/Actions/Items/InsertSocketPlugFree",
1016            json=body,
1017            auth=access_token,
1018        )
1019        assert isinstance(resp, dict)
1020        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (aiobungie.builders.PlugSocketBuilder | Mapping[str, int]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.aiobungie.MembershipType | int The membership type.

Returns
Raises
@helpers.unstable
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: MembershipType | int) -> int:
1022    @helpers.unstable
1023    async def set_item_lock_state(
1024        self,
1025        access_token: str,
1026        state: bool,
1027        /,
1028        item_id: int,
1029        character_id: int,
1030        membership_type: enums.MembershipType | int,
1031    ) -> int:
1032        body = {
1033            "state": state,
1034            "itemId": item_id,
1035            "characterId": character_id,
1036            "membershipType": int(membership_type),
1037        }
1038        response = await self._request(
1039            _POST,
1040            "Destiny2/Actions/Items/SetLockState",
1041            json=body,
1042            auth=access_token,
1043        )
1044        assert isinstance(response, int)
1045        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: MembershipType | int) -> int:
1047    async def set_quest_track_state(
1048        self,
1049        access_token: str,
1050        state: bool,
1051        /,
1052        item_id: int,
1053        character_id: int,
1054        membership_type: enums.MembershipType | int,
1055    ) -> int:
1056        body = {
1057            "state": state,
1058            "itemId": item_id,
1059            "characterId": character_id,
1060            "membership_type": int(membership_type),
1061        }
1062        response = await self._request(
1063            _POST,
1064            "Destiny2/Actions/Items/SetTrackedState",
1065            json=body,
1066            auth=access_token,
1067        )
1068        assert isinstance(response, int)
1069        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> collections.abc.Mapping[str, typing.Any]:
1071    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1072        path = await self._request(_GET, "Destiny2/Manifest")
1073        assert isinstance(path, dict)
1074        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1076    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1077        _ensure_manifest_language(language)
1078
1079        content = await self.fetch_manifest_path()
1080        resp = await self._request(
1081            _GET,
1082            content["mobileWorldContentPaths"][language],
1083            unwrap_bytes=True,
1084            base=True,
1085        )
1086        assert isinstance(resp, bytes)
1087        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_sqlite_manifest( self, language: str = 'en', name: str = 'manifest', path: pathlib.Path | str = '.', *, force: bool = False, executor: concurrent.futures._base.Executor | None = None) -> pathlib.Path:
1089    async def download_sqlite_manifest(
1090        self,
1091        language: str = "en",
1092        name: str = "manifest",
1093        path: pathlib.Path | str = ".",
1094        *,
1095        force: bool = False,
1096        executor: concurrent.futures.Executor | None = None,
1097    ) -> pathlib.Path:
1098        complete_path = _get_path(name, path, sql=True)
1099
1100        if complete_path.exists() and force:
1101            if force:
1102                _LOGGER.info(
1103                    f"Found manifest in {complete_path!s}. Forcing to Re-Download."
1104                )
1105                complete_path.unlink(missing_ok=True)
1106
1107                return await self.download_sqlite_manifest(
1108                    language, name, path, force=force
1109                )
1110
1111            else:
1112                raise FileExistsError(
1113                    "Manifest file already exists, "
1114                    "To force download, set the `force` parameter to `True`."
1115                )
1116
1117        _LOGGER.info(f"Downloading manifest. Location: {complete_path!s}")
1118        data_bytes = await self.read_manifest_bytes(language)
1119        await asyncio.get_running_loop().run_in_executor(
1120            executor, _write_sqlite_bytes, data_bytes, path, name
1121        )
1122        _LOGGER.info("Finished downloading manifest.")
1123        return _get_path(name, path, sql=True)

Downloads the SQLite version of Destiny2's Manifest.

Example
manifest = await rest.download_sqlite_manifest()
with sqlite3.connect(manifest) as conn:
    ...
Parameters
  • language (str): The manifest language to download, Default is English.
  • path (str | pathlib.Path): The path to download this manifest. Example "/tmp/databases/", Default is the current directory.
  • name (str): The manifest database file name. Default is manifest
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get unlinked and a new one will begin to download.
  • executor (concurrent.futures.Executor | None): An optional executor which will be used to write the bytes of the manifest.
Returns
  • pathlib.Path: A pathlib object of the .sqlite file.
Raises
  • FileNotFoundError: If the manifest file exists and force is False.
  • ValueError: If the provided language was not recognized.
async def download_json_manifest( self, file_name: str = 'manifest', path: str | pathlib.Path = '.', *, language: str = 'en', executor: concurrent.futures._base.Executor | None = None) -> pathlib.Path:
1125    async def download_json_manifest(
1126        self,
1127        file_name: str = "manifest",
1128        path: str | pathlib.Path = ".",
1129        *,
1130        language: str = "en",
1131        executor: concurrent.futures.Executor | None = None,
1132    ) -> pathlib.Path:
1133        _ensure_manifest_language(language)
1134        full_path = _get_path(file_name, path)
1135        _LOGGER.info(f"Downloading manifest JSON to {full_path!r}...")
1136
1137        content = await self.fetch_manifest_path()
1138        json_bytes = await self._request(
1139            _GET,
1140            content["jsonWorldContentPaths"][language],
1141            unwrap_bytes=True,
1142            base=True,
1143        )
1144
1145        assert isinstance(json_bytes, bytes)
1146        await asyncio.get_running_loop().run_in_executor(
1147            executor, _write_json_bytes, json_bytes, file_name, path
1148        )
1149        _LOGGER.info("Finished downloading manifest JSON.")
1150        return full_path

Download the Bungie manifest json file.

Example
manifest = await rest.download_json_manifest()
with open(manifest, "r") as f:
    to_dict = json.loads(f.read())
    item_definitions = to_dict['DestinyInventoryItemDefinition']
Parameters
  • file_name (str): The file name to save the manifest json file. Default is manifest.
  • path (str | pathlib.Path): The path to save the manifest json file. Default is the current directory. Example "D:/"
  • language (str): The manifest database language bytes to get. Default is English.
  • executor (concurrent.futures.Executor | None): An optional executor which will be used to write the bytes of the manifest.
Returns
  • pathlib.Path: The path of this JSON manifest.
async def fetch_manifest_version(self) -> str:
1152    async def fetch_manifest_version(self) -> str:
1153        # This is guaranteed str.
1154        return (await self.fetch_manifest_path())["version"]

Fetch the manifest version.

Returns
  • str: The manifest version.
async def fetch_linked_profiles( self, member_id: int, member_type: MembershipType | int, /, *, all: bool = False) -> collections.abc.Mapping[str, typing.Any]:
1156    async def fetch_linked_profiles(
1157        self,
1158        member_id: int,
1159        member_type: enums.MembershipType | int,
1160        /,
1161        *,
1162        all: bool = False,
1163    ) -> typedefs.JSONObject:
1164        resp = await self._request(
1165            _GET,
1166            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1167        )
1168        assert isinstance(resp, dict)
1169        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.aiobungie.MembershipType | int): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> collections.abc.Mapping[str, typing.Any]:
1171    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1172        resp = await self._request(_GET, "Destiny2/Clan/ClanBannerDictionary/")
1173        assert isinstance(resp, dict)
1174        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> collections.abc.Mapping[str, typing.Any]:
1176    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1177        resp = await self._request(_GET, "Destiny2/Milestones/")
1178        assert isinstance(resp, dict)
1179        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> collections.abc.Mapping[str, typing.Any]:
1181    async def fetch_public_milestone_content(
1182        self, milestone_hash: int, /
1183    ) -> typedefs.JSONObject:
1184        resp = await self._request(
1185            _GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1186        )
1187        assert isinstance(resp, dict)
1188        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> collections.abc.Mapping[str, typing.Any]:
1190    async def fetch_current_user_memberships(
1191        self, access_token: str, /
1192    ) -> typedefs.JSONObject:
1193        resp = await self._request(
1194            _GET,
1195            "User/GetMembershipsForCurrentUser/",
1196            auth=access_token,
1197        )
1198        assert isinstance(resp, dict)
1199        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: MembershipType | int) -> None:
1201    async def equip_item(
1202        self,
1203        access_token: str,
1204        /,
1205        item_id: int,
1206        character_id: int,
1207        membership_type: enums.MembershipType | int,
1208    ) -> None:
1209        payload = {
1210            "itemId": item_id,
1211            "characterId": character_id,
1212            "membershipType": int(membership_type),
1213        }
1214
1215        await self._request(
1216            _POST,
1217            "Destiny2/Actions/Items/EquipItem/",
1218            json=payload,
1219            auth=access_token,
1220        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type associated with this player.
async def equip_items( self, access_token: str, /, item_ids: collections.abc.Sequence[int], character_id: int, membership_type: MembershipType | int) -> None:
1222    async def equip_items(
1223        self,
1224        access_token: str,
1225        /,
1226        item_ids: collections.Sequence[int],
1227        character_id: int,
1228        membership_type: enums.MembershipType | int,
1229    ) -> None:
1230        payload = {
1231            "itemIds": item_ids,
1232            "characterId": character_id,
1233            "membershipType": int(membership_type),
1234        }
1235        await self._request(
1236            _POST,
1237            "Destiny2/Actions/Items/EquipItems/",
1238            json=payload,
1239            auth=access_token,
1240        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (Sequence[int]): A sequence of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type associated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int, *, length: int = 0, comment: str | None = None) -> None:
1242    async def ban_clan_member(
1243        self,
1244        access_token: str,
1245        /,
1246        group_id: int,
1247        membership_id: int,
1248        membership_type: enums.MembershipType | int,
1249        *,
1250        length: int = 0,
1251        comment: str | None = None,
1252    ) -> None:
1253        payload = {"comment": str(comment), "length": length}
1254        await self._request(
1255            _POST,
1256            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1257            json=payload,
1258            auth=access_token,
1259        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Other Parameters
  • length (int): An optional ban length.
  • comment (aiobungie.UndefinedOr[str]): An optional comment to this ban. Default is UNDEFINED
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> None:
1261    async def unban_clan_member(
1262        self,
1263        access_token: str,
1264        /,
1265        group_id: int,
1266        membership_id: int,
1267        membership_type: enums.MembershipType | int,
1268    ) -> None:
1269        await self._request(
1270            _POST,
1271            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1272            auth=access_token,
1273        )

Unban a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
1275    async def kick_clan_member(
1276        self,
1277        access_token: str,
1278        /,
1279        group_id: int,
1280        membership_id: int,
1281        membership_type: enums.MembershipType | int,
1282    ) -> typedefs.JSONObject:
1283        resp = await self._request(
1284            _POST,
1285            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1286            auth=access_token,
1287        )
1288        assert isinstance(resp, dict)
1289        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: str | None = None, about: str | None = None, motto: str | None = None, theme: str | None = None, tags: collections.abc.Sequence[str] | None = None, is_public: bool | None = None, locale: str | None = None, avatar_image_index: int | None = None, membership_option: MembershipOption | int | None = None, allow_chat: bool | None = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: str | None = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: bool | None = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: bool | None = None) -> None:
1291    async def edit_clan(
1292        self,
1293        access_token: str,
1294        /,
1295        group_id: int,
1296        *,
1297        name: str | None = None,
1298        about: str | None = None,
1299        motto: str | None = None,
1300        theme: str | None = None,
1301        tags: collections.Sequence[str] | None = None,
1302        is_public: bool | None = None,
1303        locale: str | None = None,
1304        avatar_image_index: int | None = None,
1305        membership_option: enums.MembershipOption | int | None = None,
1306        allow_chat: bool | None = None,
1307        chat_security: typing.Literal[0, 1] | None = None,
1308        call_sign: str | None = None,
1309        homepage: typing.Literal[0, 1, 2] | None = None,
1310        enable_invite_messaging_for_admins: bool | None = None,
1311        default_publicity: typing.Literal[0, 1, 2] | None = None,
1312        is_public_topic_admin: bool | None = None,
1313    ) -> None:
1314        payload = {
1315            "name": name,
1316            "about": about,
1317            "motto": motto,
1318            "theme": theme,
1319            "tags": tags,
1320            "isPublic": is_public,
1321            "avatarImageIndex": avatar_image_index,
1322            "isPublicTopicAdminOnly": is_public_topic_admin,
1323            "allowChat": allow_chat,
1324            "chatSecurity": chat_security,
1325            "callsign": call_sign,
1326            "homepage": homepage,
1327            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1328            "defaultPublicity": default_publicity,
1329            "locale": locale,
1330        }
1331        if membership_option is not None:
1332            payload["membershipOption"] = int(membership_option)
1333
1334        await self._request(
1335            _POST,
1336            f"GroupV2/{group_id}/Edit",
1337            json=payload,
1338            auth=access_token,
1339        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
  • name (str | None): The name to edit the clan with.
  • about (str | None): The about section to edit the clan with.
  • motto (str | None): The motto section to edit the clan with.
  • theme (str | None): The theme name to edit the clan with.
  • tags (collections.Sequence[str] | None): A sequence of strings to replace the clan tags with.
  • is_public (bool | None): If provided and set to True, The clan will set to private. If provided and set to False, The clan will set to public whether it was or not.
  • locale (str | None): The locale section to edit the clan with.
  • avatar_image_index (int | None): The clan avatar image index to edit the clan with.
  • membership_option : aiobungie.typedefs.NoneOr[aiobungie.aiobungie.MembershipOption | int] # noqa (E501 # Line too long): The clan membership option to edit it with.
  • allow_chat (bool | None): If provided and set to True, The clan members will be allowed to chat. If provided and set to False, The clan members will not be allowed to chat.
  • chat_security (aiobungie.typedefs.NoneOr[typing.Literal[0, 1]]): If provided and set to 0, The clan chat security will be edited to Group only. If provided and set to 1, The clan chat security will be edited to Admin only.
  • call_sign (str | None): The clan call sign to edit it with.
  • homepage (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to 0, The clan chat homepage will be edited to Wall. If provided and set to 1, The clan chat homepage will be edited to Forum. If provided and set to 0, The clan chat homepage will be edited to AllianceForum.
  • enable_invite_messaging_for_admins (bool | None): ???
  • default_publicity (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): If provided and set to 0, The clan chat publicity will be edited to Public. If provided and set to 1, The clan chat publicity will be edited to Alliance. If provided and set to 2, The clan chat publicity will be edited to Private.
  • is_public_topic_admin (bool | None): ???
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: bool | None = None, update_culture_permissionOverride: bool | None = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: bool | None = None, join_level: ClanMemberType | int | None = None) -> None:
1341    async def edit_clan_options(
1342        self,
1343        access_token: str,
1344        /,
1345        group_id: int,
1346        *,
1347        invite_permissions_override: bool | None = None,
1348        update_culture_permissionOverride: bool | None = None,
1349        host_guided_game_permission_override: typing.Literal[0, 1, 2] | None = None,
1350        update_banner_permission_override: bool | None = None,
1351        join_level: enums.ClanMemberType | int | None = None,
1352    ) -> None:
1353        payload = {
1354            "InvitePermissionOverride": invite_permissions_override,
1355            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1356            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1357            "UpdateBannerPermissionOverride": update_banner_permission_override,
1358            "JoinLevel": int(join_level) if join_level else None,
1359        }
1360
1361        await self._request(
1362            _POST,
1363            f"GroupV2/{group_id}/EditFounderOptions",
1364            json=payload,
1365            auth=access_token,
1366        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (bool | None): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (bool | None): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (bool | None): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> collections.abc.Mapping[str, typing.Any]:
1368    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1369        resp = await self._request(
1370            _GET,
1371            "Social/Friends/",
1372            auth=access_token,
1373        )
1374        assert isinstance(resp, dict)
1375        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> collections.abc.Mapping[str, typing.Any]:
1377    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1378        resp = await self._request(
1379            _GET,
1380            "Social/Friends/Requests",
1381            auth=access_token,
1382        )
1383        assert isinstance(resp, dict)
1384        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1386    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1387        await self._request(
1388            _POST,
1389            f"Social/Friends/Requests/Accept/{member_id}",
1390            auth=access_token,
1391        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1393    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1394        await self._request(
1395            _POST,
1396            f"Social/Friends/Add/{member_id}",
1397            auth=access_token,
1398        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1400    async def decline_friend_request(
1401        self, access_token: str, /, member_id: int
1402    ) -> None:
1403        await self._request(
1404            _POST,
1405            f"Social/Friends/Requests/Decline/{member_id}",
1406            auth=access_token,
1407        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1409    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1410        await self._request(
1411            _POST,
1412            f"Social/Friends/Remove/{member_id}",
1413            auth=access_token,
1414        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1416    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1417        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1418        await self._request(
1419            _POST,
1420            f"Social/Friends/Requests/Remove/{member_id}",
1421            auth=access_token,
1422        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: str | None = None) -> None:
1424    async def approve_all_pending_group_users(
1425        self,
1426        access_token: str,
1427        /,
1428        group_id: int,
1429        message: str | None = None,
1430    ) -> None:
1431        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1432        await self._request(
1433            _POST,
1434            f"GroupV2/{group_id}/Members/ApproveAll",
1435            auth=access_token,
1436            json={"message": str(message)},
1437        )

Approve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: str | None = None) -> None:
1439    async def deny_all_pending_group_users(
1440        self,
1441        access_token: str,
1442        /,
1443        group_id: int,
1444        *,
1445        message: str | None = None,
1446    ) -> None:
1447        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1448        await self._request(
1449            _POST,
1450            f"GroupV2/{group_id}/Members/DenyAll",
1451            auth=access_token,
1452            json={"message": str(message)},
1453        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: str | None = None, security: Literal[0, 1] = 0) -> None:
1455    async def add_optional_conversation(
1456        self,
1457        access_token: str,
1458        /,
1459        group_id: int,
1460        *,
1461        name: str | None = None,
1462        security: typing.Literal[0, 1] = 0,
1463    ) -> None:
1464        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1465        payload = {"chatName": str(name), "chatSecurity": security}
1466        await self._request(
1467            _POST,
1468            f"GroupV2/{group_id}/OptionalConversations/Add",
1469            json=payload,
1470            auth=access_token,
1471        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: str | None = None, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1473    async def edit_optional_conversation(
1474        self,
1475        access_token: str,
1476        /,
1477        group_id: int,
1478        conversation_id: int,
1479        *,
1480        name: str | None = None,
1481        security: typing.Literal[0, 1] = 0,
1482        enable_chat: bool = False,
1483    ) -> None:
1484        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1485        payload = {
1486            "chatEnabled": enable_chat,
1487            "chatName": str(name),
1488            "chatSecurity": security,
1489        }
1490        await self._request(
1491            _POST,
1492            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1493            json=payload,
1494            auth=access_token,
1495        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: MembershipType | int, *, stack_size: int = 1, vault: bool = False) -> None:
1497    async def transfer_item(
1498        self,
1499        access_token: str,
1500        /,
1501        item_id: int,
1502        item_hash: int,
1503        character_id: int,
1504        member_type: enums.MembershipType | int,
1505        *,
1506        stack_size: int = 1,
1507        vault: bool = False,
1508    ) -> None:
1509        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1510        payload = {
1511            "characterId": character_id,
1512            "membershipType": int(member_type),
1513            "itemId": item_id,
1514            "itemReferenceHash": item_hash,
1515            "stackSize": stack_size,
1516            "transferToVault": vault,
1517        }
1518        await self._request(
1519            _POST,
1520            "Destiny2/Actions/Items/TransferItem",
1521            json=payload,
1522            auth=access_token,
1523        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.aiobungie.MembershipType | int): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • vault (bool): Whether to transfer this item to your vault or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: MembershipType | int, *, stack_size: int = 1, vault: bool = False) -> None:
1525    async def pull_item(
1526        self,
1527        access_token: str,
1528        /,
1529        item_id: int,
1530        item_hash: int,
1531        character_id: int,
1532        member_type: enums.MembershipType | int,
1533        *,
1534        stack_size: int = 1,
1535        vault: bool = False,
1536    ) -> None:
1537        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1538        payload = {
1539            "characterId": character_id,
1540            "membershipType": int(member_type),
1541            "itemId": item_id,
1542            "itemReferenceHash": item_hash,
1543            "stackSize": stack_size,
1544            "transferToVault": vault,
1545        }
1546        await self._request(
1547            _POST,
1548            "Destiny2/Actions/Items/PullFromPostmaster",
1549            json=payload,
1550            auth=access_token,
1551        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.aiobungie.MembershipType | int): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • vault (bool): Whether to pill this item to your vault or not. Defaults to False.
async def fetch_fireteams( self, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int = <FireteamPlatform.ANY: 0>, language: FireteamLanguage | str = <FireteamLanguage.ALL: >, date_range: FireteamDate | int = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1553    async def fetch_fireteams(
1554        self,
1555        activity_type: fireteams.FireteamActivity | int,
1556        *,
1557        platform: fireteams.FireteamPlatform | int = fireteams.FireteamPlatform.ANY,
1558        language: fireteams.FireteamLanguage | str = fireteams.FireteamLanguage.ALL,
1559        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1560        page: int = 0,
1561        slots_filter: int = 0,
1562    ) -> typedefs.JSONObject:
1563        resp = await self._request(
1564            _GET,
1565            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1566        )
1567        assert isinstance(resp, dict)
1568        return resp

Fetch public Bungie fireteams with open slots.

Parameters
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.aiobungie.FireteamDate | int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_available_clan_fireteams( self, access_token: str, group_id: int, activity_type: FireteamActivity | int, *, platform: FireteamPlatform | int, language: FireteamLanguage | str, date_range: FireteamDate | int = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1570    async def fetch_available_clan_fireteams(
1571        self,
1572        access_token: str,
1573        group_id: int,
1574        activity_type: fireteams.FireteamActivity | int,
1575        *,
1576        platform: fireteams.FireteamPlatform | int,
1577        language: fireteams.FireteamLanguage | str,
1578        date_range: fireteams.FireteamDate | int = fireteams.FireteamDate.ALL,
1579        page: int = 0,
1580        public_only: bool = False,
1581        slots_filter: int = 0,
1582    ) -> typedefs.JSONObject:
1583        resp = await self._request(
1584            _GET,
1585            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1586            json={"langFilter": str(language)},
1587            auth=access_token,
1588        )
1589        assert isinstance(resp, dict)
1590        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.aiobungie.crates.FireteamActivity | int): The fireteam activity type.
Other Parameters
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.aiobungie.FireteamDate | int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> collections.abc.Mapping[str, typing.Any]:
1592    async def fetch_clan_fireteam(
1593        self, access_token: str, fireteam_id: int, group_id: int
1594    ) -> typedefs.JSONObject:
1595        resp = await self._request(
1596            _GET,
1597            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1598            auth=access_token,
1599        )
1600        assert isinstance(resp, dict)
1601        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: FireteamPlatform | int, language: FireteamLanguage | str, filtered: bool = True, page: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1603    async def fetch_my_clan_fireteams(
1604        self,
1605        access_token: str,
1606        group_id: int,
1607        *,
1608        include_closed: bool = True,
1609        platform: fireteams.FireteamPlatform | int,
1610        language: fireteams.FireteamLanguage | str,
1611        filtered: bool = True,
1612        page: int = 0,
1613    ) -> typedefs.JSONObject:
1614        payload = {"groupFilter": filtered, "langFilter": str(language)}
1615
1616        resp = await self._request(
1617            _GET,
1618            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1619            json=payload,
1620            auth=access_token,
1621        )
1622        assert isinstance(resp, dict)
1623        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.aiobungie.crates.fireteams.FireteamPlatform | int): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (FireteamLanguage | str): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1625    async def fetch_private_clan_fireteams(
1626        self, access_token: str, group_id: int, /
1627    ) -> int:
1628        resp = await self._request(
1629            _GET,
1630            f"Fireteam/Clan/{group_id}/ActiveCount",
1631            auth=access_token,
1632        )
1633        assert isinstance(resp, int)
1634        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
1636    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1637        resp = await self._request(
1638            _GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1639        )
1640        assert isinstance(resp, dict)
1641        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> collections.abc.Mapping[str, typing.Any]:
1643    async def search_entities(
1644        self, name: str, entity_type: str, *, page: int = 0
1645    ) -> typedefs.JSONObject:
1646        resp = await self._request(
1647            _GET,
1648            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1649            json={"page": page},
1650        )
1651        assert isinstance(resp, dict)
1652        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
1654    async def fetch_unique_weapon_history(
1655        self,
1656        membership_id: int,
1657        character_id: int,
1658        membership_type: enums.MembershipType | int,
1659    ) -> typedefs.JSONObject:
1660        resp = await self._request(
1661            _GET,
1662            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1663        )
1664        assert isinstance(resp, dict)
1665        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
  • membership_id (int): The Destiny user membership id.
  • character_id (int): The character id to retrieve.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny user's membership type.
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: MembershipType | int, components: collections.abc.Sequence[ComponentType]) -> collections.abc.Mapping[str, typing.Any]:
1667    async def fetch_item(
1668        self,
1669        member_id: int,
1670        item_id: int,
1671        membership_type: enums.MembershipType | int,
1672        components: collections.Sequence[enums.ComponentType],
1673    ) -> typedefs.JSONObject:
1674        collector = _collect_components(components)
1675
1676        resp = await self._request(
1677            _GET,
1678            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1679        )
1680        assert isinstance(resp, dict)
1681        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
  • member_id (int): The membership id of the Destiny 2 player.
  • item_id (int): The instance id of the item.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The membership type of the Destiny 2 player.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of components to retrieve.
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
1683    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1684        resp = await self._request(_GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/")
1685        assert isinstance(resp, dict)
1686        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> collections.abc.Mapping[str, typing.Any]:
1688    async def fetch_available_locales(self) -> typedefs.JSONObject:
1689        resp = await self._request(_GET, "Destiny2/Manifest/DestinyLocaleDefinition/")
1690        assert isinstance(resp, dict)
1691        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> collections.abc.Mapping[str, typing.Any]:
1693    async def fetch_common_settings(self) -> typedefs.JSONObject:
1694        resp = await self._request(_GET, "Settings")
1695        assert isinstance(resp, dict)
1696        return resp

Fetch the common settings used by Bungie's environment.

Returns
async def fetch_user_systems_overrides(self) -> collections.abc.Mapping[str, typing.Any]:
1698    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1699        resp = await self._request(_GET, "UserSystemOverrides")
1700        assert isinstance(resp, dict)
1701        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts( self, *, include_streaming: bool = False) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
1703    async def fetch_global_alerts(
1704        self, *, include_streaming: bool = False
1705    ) -> typedefs.JSONArray:
1706        resp = await self._request(
1707            _GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1708        )
1709        assert isinstance(resp, list)
1710        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: MembershipType | int, /, *, affected_item_id: int | None = None, character_id: int | None = None) -> collections.abc.Mapping[str, typing.Any]:
1712    async def awainitialize_request(
1713        self,
1714        access_token: str,
1715        type: typing.Literal[0, 1],
1716        membership_type: enums.MembershipType | int,
1717        /,
1718        *,
1719        affected_item_id: int | None = None,
1720        character_id: int | None = None,
1721    ) -> typedefs.JSONObject:
1722        body = {"type": type, "membershipType": int(membership_type)}
1723
1724        if affected_item_id is not None:
1725            body["affectedItemId"] = affected_item_id
1726
1727        if character_id is not None:
1728            body["characterId"] = character_id
1729
1730        resp = await self._request(
1731            _POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1732        )
1733        assert isinstance(resp, dict)
1734        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (int | None): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (int | None): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token( self, access_token: str, correlation_id: str, /) -> collections.abc.Mapping[str, typing.Any]:
1736    async def awaget_action_token(
1737        self, access_token: str, correlation_id: str, /
1738    ) -> typedefs.JSONObject:
1739        resp = await self._request(
1740            _POST,
1741            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1742            auth=access_token,
1743        )
1744        assert isinstance(resp, dict)
1745        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[str | bytes]) -> int:
1747    async def awa_provide_authorization_result(
1748        self,
1749        access_token: str,
1750        selection: int,
1751        correlation_id: str,
1752        nonce: collections.MutableSequence[str | bytes],
1753    ) -> int:
1754        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1755
1756        resp = await self._request(
1757            _POST,
1758            "Destiny2/Awa/AwaProvideAuthorizationResult",
1759            json=body,
1760            auth=access_token,
1761        )
1762        assert isinstance(resp, int)
1763        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str | bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: MembershipType | int, /, components: collections.abc.Sequence[ComponentType], filter: int | None = None) -> collections.abc.Mapping[str, typing.Any]:
1765    async def fetch_vendors(
1766        self,
1767        access_token: str,
1768        character_id: int,
1769        membership_id: int,
1770        membership_type: enums.MembershipType | int,
1771        /,
1772        components: collections.Sequence[enums.ComponentType],
1773        filter: int | None = None,
1774    ) -> typedefs.JSONObject:
1775        components_ = _collect_components(components)
1776        route = (
1777            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1778            f"/Character/{character_id}/Vendors/?components={components_}"
1779        )
1780
1781        if filter is not None:
1782            route = route + f"&filter={filter}"
1783
1784        resp = await self._request(
1785            _GET,
1786            route,
1787            auth=access_token,
1788        )
1789        assert isinstance(resp, dict)
1790        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny membership type to return the vendor info for.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: MembershipType | int, vendor_hash: int, /, components: collections.abc.Sequence[ComponentType]) -> collections.abc.Mapping[str, typing.Any]:
1792    async def fetch_vendor(
1793        self,
1794        access_token: str,
1795        character_id: int,
1796        membership_id: int,
1797        membership_type: enums.MembershipType | int,
1798        vendor_hash: int,
1799        /,
1800        components: collections.Sequence[enums.ComponentType],
1801    ) -> typedefs.JSONObject:
1802        components_ = _collect_components(components)
1803        resp = await self._request(
1804            _GET,
1805            (
1806                f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1807                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1808            ),
1809            auth=access_token,
1810        )
1811        assert isinstance(resp, dict)
1812        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.aiobungie.MembershipType | int): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (collections.Sequence[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: datetime.datetime | None = None, end: datetime.datetime | None = None) -> collections.abc.Mapping[str, typing.Any]:
1814    async def fetch_application_api_usage(
1815        self,
1816        access_token: str,
1817        application_id: int,
1818        /,
1819        *,
1820        start: datetime.datetime | None = None,
1821        end: datetime.datetime | None = None,
1822    ) -> typedefs.JSONObject:
1823        end_date, start_date = time.parse_date_range(end, start)
1824        resp = await self._request(
1825            _GET,
1826            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1827            auth=access_token,
1828        )
1829        assert isinstance(resp, dict)
1830        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (datetime.datetime | None): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (datetime.datetime | None): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10),
    end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications( self) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
1832    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1833        resp = await self._request(_GET, "App/FirstParty")
1834        assert isinstance(resp, list)
1835        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> collections.abc.Mapping[str, typing.Any]:
1837    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1838        resp = await self._request(_GET, f"Content/GetContentType/{type}/")
1839        assert isinstance(resp, dict)
1840        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> collections.abc.Mapping[str, typing.Any]:
1842    async def fetch_content_by_id(
1843        self, id: int, locale: str, /, *, head: bool = False
1844    ) -> typedefs.JSONObject:
1845        resp = await self._request(
1846            _GET,
1847            f"Content/GetContentById/{id}/{locale}/",
1848            json={"head": head},
1849        )
1850        assert isinstance(resp, dict)
1851        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> collections.abc.Mapping[str, typing.Any]:
1853    async def fetch_content_by_tag_and_type(
1854        self, locale: str, tag: str, type: str, *, head: bool = False
1855    ) -> typedefs.JSONObject:
1856        resp = await self._request(
1857            _GET,
1858            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1859            json={"head": head},
1860        )
1861        assert isinstance(resp, dict)
1862        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: int | None = None, source: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1864    async def search_content_with_text(
1865        self,
1866        locale: str,
1867        /,
1868        content_type: str,
1869        search_text: str,
1870        tag: str,
1871        *,
1872        page: int | None = None,
1873        source: str | None = None,
1874    ) -> typedefs.JSONObject:
1875        body: typedefs.JSONObject = {
1876            "locale": locale,
1877            "currentpage": page or 1,
1878            "ctype": content_type,
1879            "searchtxt": search_text,
1880            "searchtext": search_text,
1881            "tag": tag,
1882            "source": source,
1883        }
1884
1885        resp = await self._request(_GET, "Content/Search", params=body)
1886        assert isinstance(resp, dict)
1887        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: int | None = None) -> collections.abc.Mapping[str, typing.Any]:
1889    async def search_content_by_tag_and_type(
1890        self,
1891        locale: str,
1892        tag: str,
1893        type: str,
1894        *,
1895        page: int | None = None,
1896    ) -> typedefs.JSONObject:
1897        body: typedefs.JSONObject = {"currentpage": page or 1}
1898
1899        resp = await self._request(
1900            _GET,
1901            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
1902            params=body,
1903        )
1904        assert isinstance(resp, dict)
1905        return resp
async def search_help_articles( self, text: str, size: str, /) -> collections.abc.Mapping[str, typing.Any]:
1907    async def search_help_articles(
1908        self, text: str, size: str, /
1909    ) -> typedefs.JSONObject:
1910        resp = await self._request(_GET, f"Content/SearchHelpArticles/{text}/{size}/")
1911        assert isinstance(resp, dict)
1912        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: str | bytes, *, page: int | None = None, locales: collections.abc.Iterable[str] | None = None, tag_filter: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1914    async def fetch_topics_page(
1915        self,
1916        category_filter: int,
1917        group: int,
1918        date_filter: int,
1919        sort: str | bytes,
1920        *,
1921        page: int | None = None,
1922        locales: collections.Iterable[str] | None = None,
1923        tag_filter: str | None = None,
1924    ) -> typedefs.JSONObject:
1925        params = {
1926            "locales": ",".join(locales) if locales is not None else "en",
1927        }
1928        if tag_filter:
1929            params["tagstring"] = tag_filter
1930
1931        resp = await self._request(
1932            _GET,
1933            f"Forum/GetTopicsPaged/{page or 0}/0/{group}/{sort!s}/{date_filter}/{category_filter}/",
1934            params=params,
1935        )
1936        assert isinstance(resp, dict)
1937        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: str | bytes, *, page: int | None = None, locales: collections.abc.Iterable[str] | None = None) -> collections.abc.Mapping[str, typing.Any]:
1939    async def fetch_core_topics_page(
1940        self,
1941        category_filter: int,
1942        date_filter: int,
1943        sort: str | bytes,
1944        *,
1945        page: int | None = None,
1946        locales: collections.Iterable[str] | None = None,
1947    ) -> typedefs.JSONObject:
1948        resp = await self._request(
1949            _GET,
1950            f"Forum/GetCoreTopicsPaged/{page or 0}"
1951            f"/{sort!s}/{date_filter}/{category_filter}/?locales={','.join(locales) if locales else 'en'}",
1952        )
1953        assert isinstance(resp, dict)
1954        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1956    async def fetch_posts_threaded_page(
1957        self,
1958        parent_post: bool,
1959        page: int,
1960        page_size: int,
1961        parent_post_id: int,
1962        reply_size: int,
1963        root_thread_mode: bool,
1964        sort_mode: int,
1965        show_banned: str | None = None,
1966    ) -> typedefs.JSONObject:
1967        resp = await self._request(
1968            _GET,
1969            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
1970            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
1971            json={"showbanned": show_banned},
1972        )
1973        assert isinstance(resp, dict)
1974        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1976    async def fetch_posts_threaded_page_from_child(
1977        self,
1978        child_id: bool,
1979        page: int,
1980        page_size: int,
1981        reply_size: int,
1982        root_thread_mode: bool,
1983        sort_mode: int,
1984        show_banned: str | None = None,
1985    ) -> typedefs.JSONObject:
1986        resp = await self._request(
1987            _GET,
1988            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
1989            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
1990            json={"showbanned": show_banned},
1991        )
1992        assert isinstance(resp, dict)
1993        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
1995    async def fetch_post_and_parent(
1996        self, child_id: int, /, *, show_banned: str | None = None
1997    ) -> typedefs.JSONObject:
1998        resp = await self._request(
1999            _GET,
2000            f"Forum/GetPostAndParent/{child_id}/",
2001            json={"showbanned": show_banned},
2002        )
2003        assert isinstance(resp, dict)
2004        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
2006    async def fetch_posts_and_parent_awaiting(
2007        self, child_id: int, /, *, show_banned: str | None = None
2008    ) -> typedefs.JSONObject:
2009        resp = await self._request(
2010            _GET,
2011            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2012            json={"showbanned": show_banned},
2013        )
2014        assert isinstance(resp, dict)
2015        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2017    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2018        resp = await self._request(_GET, f"Forum/GetTopicForContent/{content_id}/")
2019        assert isinstance(resp, int)
2020        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> collections.abc.Mapping[str, typing.Any]:
2022    async def fetch_forum_tag_suggestions(
2023        self, partial_tag: str, /
2024    ) -> typedefs.JSONObject:
2025        resp = await self._request(
2026            _GET,
2027            "Forum/GetForumTagSuggestions/",
2028            json={"partialtag": partial_tag},
2029        )
2030        assert isinstance(resp, dict)
2031        return resp
async def fetch_poll(self, topic_id: int, /) -> collections.abc.Mapping[str, typing.Any]:
2033    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2034        resp = await self._request(_GET, f"Forum/Poll/{topic_id}/")
2035        assert isinstance(resp, dict)
2036        return resp
async def fetch_recruitment_thread_summaries( self) -> collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]:
2038    async def fetch_recruitment_thread_summaries(self) -> typedefs.JSONArray:
2039        resp = await self._request(_POST, "Forum/Recruit/Summaries/")
2040        assert isinstance(resp, list)
2041        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2059    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2060        resp = await self._request(_GET, "GroupV2/GetAvailableAvatars/")
2061        assert isinstance(resp, dict)
2062        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: MembershipType | int) -> bool:
2064    async def fetch_user_clan_invite_setting(
2065        self,
2066        access_token: str,
2067        /,
2068        membership_type: enums.MembershipType | int,
2069    ) -> bool:
2070        resp = await self._request(
2071            _GET,
2072            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2073            auth=access_token,
2074        )
2075        assert isinstance(resp, bool)
2076        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> collections.abc.Mapping[str, typing.Any]:
2078    async def fetch_banned_group_members(
2079        self, access_token: str, group_id: int, /, *, page: int = 1
2080    ) -> typedefs.JSONObject:
2081        resp = await self._request(
2082            _GET,
2083            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2084            auth=access_token,
2085        )
2086        assert isinstance(resp, dict)
2087        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> collections.abc.Mapping[str, typing.Any]:
2089    async def fetch_pending_group_memberships(
2090        self, access_token: str, group_id: int, /, *, current_page: int = 1
2091    ) -> typedefs.JSONObject:
2092        resp = await self._request(
2093            _GET,
2094            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2095            auth=access_token,
2096        )
2097        assert isinstance(resp, dict)
2098        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> collections.abc.Mapping[str, typing.Any]:
2100    async def fetch_invited_group_memberships(
2101        self, access_token: str, group_id: int, /, *, current_page: int = 1
2102    ) -> typedefs.JSONObject:
2103        resp = await self._request(
2104            _GET,
2105            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2106            auth=access_token,
2107        )
2108        assert isinstance(resp, dict)
2109        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int, *, message: str | None = None) -> collections.abc.Mapping[str, typing.Any]:
2111    async def invite_member_to_group(
2112        self,
2113        access_token: str,
2114        /,
2115        group_id: int,
2116        membership_id: int,
2117        membership_type: enums.MembershipType | int,
2118        *,
2119        message: str | None = None,
2120    ) -> typedefs.JSONObject:
2121        resp = await self._request(
2122            _POST,
2123            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2124            auth=access_token,
2125            json={"message": str(message)},
2126        )
2127        assert isinstance(resp, dict)
2128        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: MembershipType | int) -> collections.abc.Mapping[str, typing.Any]:
2130    async def cancel_group_member_invite(
2131        self,
2132        access_token: str,
2133        /,
2134        group_id: int,
2135        membership_id: int,
2136        membership_type: enums.MembershipType | int,
2137    ) -> typedefs.JSONObject:
2138        resp = await self._request(
2139            _POST,
2140            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2141            auth=access_token,
2142        )
2143        assert isinstance(resp, dict)
2144        return resp
async def fetch_historical_definition(self) -> collections.abc.Mapping[str, typing.Any]:
2146    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2147        resp = await self._request(_GET, "Destiny2/Stats/Definition/")
2148        assert isinstance(resp, dict)
2149        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: MembershipType | int, day_start: datetime.datetime, day_end: datetime.datetime, groups: collections.abc.Sequence[aiobungie.internal.enums.StatsGroupType | int], modes: collections.abc.Sequence[GameMode | int], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> collections.abc.Mapping[str, typing.Any]:
2151    async def fetch_historical_stats(
2152        self,
2153        character_id: int,
2154        membership_id: int,
2155        membership_type: enums.MembershipType | int,
2156        day_start: datetime.datetime,
2157        day_end: datetime.datetime,
2158        groups: collections.Sequence[enums.StatsGroupType | int],
2159        modes: collections.Sequence[enums.GameMode | int],
2160        *,
2161        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2162    ) -> typedefs.JSONObject:
2163        end, start = time.parse_date_range(day_end, day_start)
2164        resp = await self._request(
2165            _GET,
2166            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2167            json={
2168                "dayend": end,
2169                "daystart": start,
2170                "groups": [str(int(group)) for group in groups],
2171                "modes": [str(int(mode)) for mode in modes],
2172                "periodType": int(period_type),
2173            },
2174        )
2175        assert isinstance(resp, dict)
2176        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (collections.Sequence[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (collections.Sequence[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: MembershipType | int, groups: collections.abc.Sequence[aiobungie.internal.enums.StatsGroupType | int]) -> collections.abc.Mapping[str, typing.Any]:
2178    async def fetch_historical_stats_for_account(
2179        self,
2180        membership_id: int,
2181        membership_type: enums.MembershipType | int,
2182        groups: collections.Sequence[enums.StatsGroupType | int],
2183    ) -> typedefs.JSONObject:
2184        resp = await self._request(
2185            _GET,
2186            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2187            json={"groups": [str(int(group)) for group in groups]},
2188        )
2189        assert isinstance(resp, dict)
2190        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (collections.Sequence[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: MembershipType | int, /) -> collections.abc.Mapping[str, typing.Any]:
2192    async def fetch_aggregated_activity_stats(
2193        self,
2194        character_id: int,
2195        membership_id: int,
2196        membership_type: enums.MembershipType | int,
2197        /,
2198    ) -> typedefs.JSONObject:
2199        resp = await self._request(
2200            _GET,
2201            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2202            f"Character/{character_id}/Stats/AggregateActivityStats/",
2203        )
2204        assert isinstance(resp, dict)
2205        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
async def equip_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int) -> None:
2207    async def equip_loadout(
2208        self,
2209        access_token: str,
2210        /,
2211        loadout_index: int,
2212        character_id: int,
2213        membership_type: enums.MembershipType | int,
2214    ) -> None:
2215        response = await self._request(
2216            _POST,
2217            "Destiny2/Actions/Loadouts/EquipLoadout/",
2218            json={
2219                "loadoutIndex": loadout_index,
2220                "characterId": character_id,
2221                "membership_type": int(membership_type),
2222            },
2223            auth=access_token,
2224        )
2225        assert isinstance(response, int)

Equip a loadout. Your character must be in a Social space, Orbit or Offline while performing this operation.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
async def snapshot_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int, *, color_hash: int | None = None, icon_hash: int | None = None, name_hash: int | None = None) -> None:
2227    async def snapshot_loadout(
2228        self,
2229        access_token: str,
2230        /,
2231        loadout_index: int,
2232        character_id: int,
2233        membership_type: enums.MembershipType | int,
2234        *,
2235        color_hash: int | None = None,
2236        icon_hash: int | None = None,
2237        name_hash: int | None = None,
2238    ) -> None:
2239        response = await self._request(
2240            _POST,
2241            "Destiny2/Actions/Loadouts/SnapshotLoadout/",
2242            auth=access_token,
2243            json={
2244                "colorHash": color_hash,
2245                "iconHash": icon_hash,
2246                "nameHash": name_hash,
2247                "loadoutIndex": loadout_index,
2248                "characterId": character_id,
2249                "membershipType": int(membership_type),
2250            },
2251        )
2252        assert isinstance(response, int)

Snapshot a loadout with the currently equipped items.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
  • color_hash (int | None): ...
  • icon_hash (int | None): ...
  • name_hash (int | None): ...
async def update_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int, *, color_hash: int | None = None, icon_hash: int | None = None, name_hash: int | None = None) -> None:
2254    async def update_loadout(
2255        self,
2256        access_token: str,
2257        /,
2258        loadout_index: int,
2259        character_id: int,
2260        membership_type: enums.MembershipType | int,
2261        *,
2262        color_hash: int | None = None,
2263        icon_hash: int | None = None,
2264        name_hash: int | None = None,
2265    ) -> None:
2266        response = await self._request(
2267            _POST,
2268            "Destiny2/Actions/Loadouts/UpdateLoadoutIdentifiers/",
2269            auth=access_token,
2270            json={
2271                "colorHash": color_hash,
2272                "iconHash": icon_hash,
2273                "nameHash": name_hash,
2274                "loadoutIndex": loadout_index,
2275                "characterId": character_id,
2276                "membershipType": int(membership_type),
2277            },
2278        )
2279        assert isinstance(response, int)

Update the loadout. Color, Icon and Name.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
Other Parameters
  • color_hash (int | None): The new color hash of the loadout to update.
  • icon_hash (int | None): The new icon hash of the loadout to update.
  • name_hash (int | None): The new name hash of the loadout to update.
async def clear_loadout( self, access_token: str, /, loadout_index: int, character_id: int, membership_type: MembershipType | int) -> None:
2281    async def clear_loadout(
2282        self,
2283        access_token: str,
2284        /,
2285        loadout_index: int,
2286        character_id: int,
2287        membership_type: enums.MembershipType | int,
2288    ) -> None:
2289        response = await self._request(
2290            _POST,
2291            "Destiny2/Actions/Loadouts/ClearLoadout/",
2292            json={
2293                "loadoutIndex": loadout_index,
2294                "characterId": character_id,
2295                "membership_type": int(membership_type),
2296            },
2297            auth=access_token,
2298        )
2299        assert isinstance(response, int)

Clear the identifiers and items of a loadout.

This operation requires MoveEquipDestinyItems OAuth2 scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • loadout_index (int): The index of the loadout to use.
  • character_id (int): The character ID to equip the loadout to.
  • membership_type (aiobungie.MembershipType | int): The membership type of the account.
class RESTPool:
193class RESTPool:
194    """a Pool of `RESTClient` instances.
195
196    This allows to acquire multiple instances of `RESTClient`s which can be acquired with the same token and metadata.
197
198    A full example of this client can be found in the examples directory.
199
200    Example
201    -------
202    ```py
203    import aiobungie
204    import asyncio
205
206    pool = aiobungie.RESTPool("token")
207    pool.metadata['auth_code'] = 'code'
208
209    async def get() -> None:
210        async with pool.acquire() as rest:
211            this = await rest.fetch_current_user_memberships(pool.metadata['auth_code'])
212
213    await asyncio.run(get())
214    ```
215
216    Parameters
217    ----------
218    token : `str`
219        A valid application token from Bungie's developer portal.
220
221    Other Parameters
222    ----------------
223    max_retries : `int`
224        The max retries number to retry if the request hit a `5xx` status code.
225    client_secret : `str | None`
226        An optional application client secret,
227        This is only needed if you're fetching OAuth2 tokens with this client.
228    client_id : `int | None`
229        An optional application client id,
230        This is only needed if you're fetching OAuth2 tokens with this client.
231    debug : `bool | str`
232        Whether to enable logging responses or not.
233
234    Logging Levels
235    --------------
236    * `False`: This will disable logging.
237    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
238    Like the response status, route, taken time and so on.
239    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
240    """
241
242    __slots__ = (
243        "_token",
244        "_max_retries",
245        "_client_secret",
246        "_client_id",
247        "_metadata",
248        "_enable_debug",
249        "_client_session",
250        "_loads",
251        "_dumps",
252    )
253
254    # Looks like mypy doesn't like this.
255    if typing.TYPE_CHECKING:
256        _enable_debug: typing.Literal["TRACE"] | bool | int
257
258    def __init__(
259        self,
260        token: str,
261        /,
262        *,
263        client_secret: str | None = None,
264        client_id: int | None = None,
265        client_session: aiohttp.ClientSession | None = None,
266        dumps: typedefs.Dumps = helpers.dumps,
267        loads: typedefs.Loads = helpers.loads,
268        max_retries: int = 4,
269        debug: typing.Literal["TRACE"] | bool | int = False,
270    ) -> None:
271        self._client_secret = client_secret
272        self._client_id = client_id
273        self._token = token
274        self._max_retries = max_retries
275        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
276        self._enable_debug = debug
277        self._client_session = client_session
278        self._loads = loads
279        self._dumps = dumps
280
281    @property
282    def client_id(self) -> int | None:
283        return self._client_id
284
285    @property
286    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
287        """Pool's Metadata. This is different from client instance metadata."""
288        return self._metadata
289
290    @typing.final
291    def acquire(self) -> RESTClient:
292        """Acquires a new `RESTClient` instance from this pool.
293
294        Returns
295        -------
296        `RESTClient`
297            An instance of a `RESTClient`.
298        """
299        return RESTClient(
300            self._token,
301            client_secret=self._client_secret,
302            client_id=self._client_id,
303            loads=self._loads,
304            dumps=self._dumps,
305            max_retries=self._max_retries,
306            debug=self._enable_debug,
307            client_session=self._client_session,
308        )

a Pool of RESTClient instances.

This allows to acquire multiple instances of RESTClients which can be acquired with the same token and metadata.

A full example of this client can be found in the examples directory.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")
pool.metadata['auth_code'] = 'code'

async def get() -> None:
    async with pool.acquire() as rest:
        this = await rest.fetch_current_user_memberships(pool.metadata['auth_code'])

await asyncio.run(get())
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • client_secret (str | None): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (int | None): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • debug (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, *, client_secret: str | None = None, client_id: int | None = None, client_session: aiohttp.client.ClientSession | None = None, dumps: collections.abc.Callable[[collections.abc.Mapping[str, typing.Any] | collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]]], bytes] = <function dumps>, loads: collections.abc.Callable[[str | bytes], collections.abc.Sequence[collections.abc.Mapping[str, typing.Any]] | collections.abc.Mapping[str, typing.Any]] = <function loads>, max_retries: int = 4, debug: Union[Literal['TRACE'], bool, int] = False)
258    def __init__(
259        self,
260        token: str,
261        /,
262        *,
263        client_secret: str | None = None,
264        client_id: int | None = None,
265        client_session: aiohttp.ClientSession | None = None,
266        dumps: typedefs.Dumps = helpers.dumps,
267        loads: typedefs.Loads = helpers.loads,
268        max_retries: int = 4,
269        debug: typing.Literal["TRACE"] | bool | int = False,
270    ) -> None:
271        self._client_secret = client_secret
272        self._client_id = client_id
273        self._token = token
274        self._max_retries = max_retries
275        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
276        self._enable_debug = debug
277        self._client_session = client_session
278        self._loads = loads
279        self._dumps = dumps
client_id: int | None
281    @property
282    def client_id(self) -> int | None:
283        return self._client_id
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]
285    @property
286    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
287        """Pool's Metadata. This is different from client instance metadata."""
288        return self._metadata

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> RESTClient:
290    @typing.final
291    def acquire(self) -> RESTClient:
292        """Acquires a new `RESTClient` instance from this pool.
293
294        Returns
295        -------
296        `RESTClient`
297            An instance of a `RESTClient`.
298        """
299        return RESTClient(
300            self._token,
301            client_secret=self._client_secret,
302            client_id=self._client_id,
303            loads=self._loads,
304            dumps=self._dumps,
305            max_retries=self._max_retries,
306            debug=self._enable_debug,
307            client_session=self._client_session,
308        )

Acquires a new RESTClient instance from this pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
485@typing.final
486class Race(int, Enum):
487    """An Enum for Destiny races."""
488
489    HUMAN = 0
490    AWOKEN = 1
491    EXO = 2
492    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
132@typing.final
133class Raid(int, Enum):
134    """An Enum for all available raids in Destiny 2."""
135
136    DSC = 910380154
137    """Deep Stone Crypt"""
138
139    LW = 2122313384
140    """Last Wish"""
141
142    VOG = 3881495763
143    """Normal Valut of Glass"""
144
145    GOS = 3458480158
146    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
250@attrs.define(auto_exc=True)
251class RateLimitedError(HTTPError):
252    """Raised when too many request status code is returned."""
253
254    http_status: http.HTTPStatus = attrs.field(
255        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
256    )
257    """The request response http status."""
258
259    url: typedefs.StrOrURL
260    """The URL/endpoint caused this error."""
261
262    body: typing.Any
263    """The response body."""
264
265    retry_after: float = attrs.field(default=0.0)
266    """The amount of seconds you need to wait before retrying to requests."""
267
268    message: str = attrs.field(init=False)
269    """A Bungie human readable message describes the cause of the error."""
270
271    # Type Ignore: attrs provide a `.default` setter on its attribs to allow
272    # changing the default value.
273    @message.default  # pyright: ignore
274    def _(self) -> str:
275        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
276
277    def __str__(self) -> str:
278        return self.message

Raised when too many request status code is returned.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
add_note
args
@typing.final
class RecordState(aiobungie.Flag):
50@typing.final
51class RecordState(enums.Flag):
52    """An enum for records component states."""
53
54    NONE = 0
55    REDEEMED = 1 << 0
56    UNAVAILABLE = 1 << 1
57    OBJECTIVE_NOT_COMPLETED = 1 << 2
58    OBSCURED = 1 << 3
59    INVISIBLE = 1 << 4
60    ENTITLEMENT_UNOWNED = 1 << 5
61    CAN_EQUIP_TITLE = 1 << 6

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
680@typing.final
681class Relationship(int, Enum):
682    """An enum for bungie friends relationship types."""
683
684    UNKNOWN = 0
685    FRIEND = 1
686    INCOMING_REQUEST = 2
687    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
245@attrs.define(auto_exc=True)
246class ResponseError(HTTPException):
247    """Exception for other HTTP response errors."""

Exception for other HTTP response errors.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class Stat(builtins.int, aiobungie.Enum):
507@typing.final
508class Stat(int, Enum):
509    """An Enum for Destiny 2 character stats."""
510
511    NONE = 0
512    MOBILITY = 2996146975
513    RESILIENCE = 392767087
514    RECOVERY = 1943323491
515    DISCIPLINE = 1735777505
516    INTELLECT = 144602215
517    STRENGTH = 4244567218
518    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
622@typing.final
623class TierType(int, Enum):
624    """An enum for a Destiny 2 item tier type."""
625
626    UNKNOWN = 0
627    CURRENCY = 1
628    BASIC = 2
629    COMMON = 3
630    RARE = 4
631    SUPERIOR = 5
632    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
732@typing.final
733class TransferStatus(Flag):
734    """An enum for items transfer statuses."""
735
736    CAN_TRANSFER = 0
737    """The item can be transferred."""
738    IS_EQUIPPED = 1 << 0
739    """You can't transfer since the item is equipped."""
740    NOT_TRASNFERRABLE = 1 << 1
741    """This item can not be transferred."""
742    COULD_BE_TRANSFERRED = 1 << 2
743    """You can transfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can transfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
154@attrs.define(auto_exc=True)
155class Unauthorized(HTTPException):
156    """An exception that's raised when trying to make unauthorized call to a resource and it returns 404."""
157
158    http_status: http.HTTPStatus = attrs.field(
159        default=http.HTTPStatus.UNAUTHORIZED, init=False
160    )

An exception that's raised when trying to make unauthorized call to a resource and it returns 404.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
add_note
args
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
74@typing.final
75class ValueUIStyle(int, enums.Enum):
76    AUTOMATIC = 0
77    FRACTION = 1
78    CHECK_BOX = 2
79    PERCENTAGE = 3
80    DATETIME = 4
81    FRACTION_FLOAT = 5
82    INTEGER = 6
83    TIME_DURATION = 7
84    HIDDEN = 8
85    MULTIPLIER = 9
86    GREEN_PIPS = 10
87    RED_PIPS = 11
88    EXPLICIT_PERCENTAGE = 12
89    RAW_FLOAT = 13
90    LEVEL_AND_REWARD = 14

int([x]) -> integer int(x, base=10) -> integer

Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating point numbers, this truncates towards zero.

If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.

>>> int('0b100', base=0)
4
AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
229@typing.final
230class Vendor(int, Enum):
231    """An Enum for all available vendors in Destiny 2."""
232
233    ZAVALA = 69482069
234    XUR = 2190858386
235    BANSHE = 672118013
236    SPIDER = 863940356
237    SHAXX = 3603221665
238    KADI = 529635856
239    """Postmaster exo."""
240    YUNA = 1796504621
241    """Asia servers only."""
242    EVERVERSE = 3361454721
243    AMANDA = 460529231
244    """Amanda holiday"""
245    CROW = 3611983588
246    HAWTHORNE = 3347378076
247    ADA1 = 350061650
248    DRIFTER = 248695599
249    IKORA = 1976548992
250    SAINT = 765357505
251    """Saint-14"""
252    ERIS_MORN = 1616085565
253    SHAW_HAWN = 1816541247
254    """COSMODROME Guy"""
255    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
521@typing.final
522class WeaponType(int, Enum):
523    """Enums for The three Destiny Weapon Types"""
524
525    NONE = 0
526    KINETIC = 1498876634
527    ENERGY = 2465295065
528    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
is_integer
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), None, 16777216)
def iter( iterable: collections.abc.Iterable[~Item]) -> Iterator[~Item]:
616def iter(
617    iterable: collections.Iterable[Item],
618) -> Iterator[Item]:
619    """Transform an iterable into an flat iterator.
620
621    Example
622    -------
623    ```py
624    sequence = (1,2,3)
625    for item in aiobungie.iter(sequence).reversed():
626        print(item)
627    # 3
628    # 2
629    # 1
630    ```
631
632    Parameters
633    ----------
634    iterable: `typing.Iterable[Item]`
635        The iterable to convert.
636
637    Raises
638    ------
639    `StopIteration`
640        If no elements are left in the iterator.
641    """
642    return Iterator(iterable)

Transform an iterable into an flat iterator.

Example
sequence = (1,2,3)
for item in aiobungie.iter(sequence).reversed():
    print(item)
# 3
# 2
# 1
Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def panic( response: aiohttp.client_reqrep.ClientResponse) -> HTTPError:
281async def panic(response: aiohttp.ClientResponse) -> HTTPError:
282    """Immediately raise an exception based on the response."""
283
284    # Bungie get funky and return HTML instead of JSON when making an authorized
285    # request with a dummy access token. We could technically read the page content
286    # but that's Bungie's fault for not returning a JSON response.
287    if response.content_type != "application/json":
288        raise HTTPError(
289            message=f"Expected JSON response, Got {response.content_type}, "
290            f"{response.real_url.human_repr()}",
291            http_status=http.HTTPStatus(response.status),
292        )
293
294    body: collections.Mapping[str, typing.Any] = helpers.loads(await response.read())  # type: ignore
295    message: str = body.get("Message", "UNDEFINED_MESSAGE")
296    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
297    message_data: dict[str, str] = body.get("MessageData", {})
298    throttle_seconds: int = body.get("ThrottleSeconds", 0)
299    error_code: int = body.get("ErrorCode", 0)
300
301    # Standard HTTP status.
302    match response.status:
303        case http.HTTPStatus.NOT_FOUND:
304            return NotFound(
305                message=message,
306                error_code=error_code,
307                throttle_seconds=throttle_seconds,
308                url=str(response.real_url),
309                body=body,
310                headers=response.headers,
311                error_status=error_status,
312                message_data=message_data,
313            )
314
315        case http.HTTPStatus.FORBIDDEN:
316            return Forbidden(
317                message=message,
318                error_code=error_code,
319                throttle_seconds=throttle_seconds,
320                url=str(response.real_url),
321                body=body,
322                headers=response.headers,
323                error_status=error_status,
324                message_data=message_data,
325            )
326
327        case http.HTTPStatus.UNAUTHORIZED:
328            return Unauthorized(
329                message=message,
330                error_code=error_code,
331                throttle_seconds=throttle_seconds,
332                url=str(response.real_url),
333                body=body,
334                headers=response.headers,
335                error_status=error_status,
336                message_data=message_data,
337            )
338
339        case http.HTTPStatus.BAD_REQUEST:
340            # Membership needs to be alone.
341            if error_status == "InvalidParameters":
342                return MembershipTypeError(
343                    message=message,
344                    body=body,
345                    headers=response.headers,
346                    url=str(response.url),
347                    membership_type=message_data["membershipType"],
348                    required_membership=message_data["membershipInfo.membershipType"],
349                    membership_id=int(message_data["membershipId"]),
350                )
351            return BadRequest(
352                message=message,
353                body=body,
354                headers=response.headers,
355                url=str(response.url),
356            )
357        case _:
358            status = http.HTTPStatus(response.status)
359
360            if 400 <= status < 500:
361                return ResponseError(
362                    message=message,
363                    error_code=error_code,
364                    throttle_seconds=throttle_seconds,
365                    url=str(response.real_url),
366                    body=body,
367                    headers=response.headers,
368                    error_status=error_status,
369                    message_data=message_data,
370                    http_status=status,
371                )
372
373            # Need to self handle ~5xx errors
374            elif 500 <= status < 600:
375                # No API key or method requires OAuth2 most likely.
376                if error_status in {
377                    "ApiKeyMissingFromRequest",
378                    "WebAuthRequired",
379                    "ApiInvalidOrExpiredKey",
380                    "AuthenticationInvalid",
381                    "AuthorizationCodeInvalid",
382                }:
383                    return Unauthorized(
384                        message=message,
385                        error_code=error_code,
386                        throttle_seconds=throttle_seconds,
387                        url=str(response.real_url),
388                        body=body,
389                        headers=response.headers,
390                        error_status=error_status,
391                        message_data=message_data,
392                    )
393
394                # Anything contains not found.
395                elif (
396                    "NotFound" in error_status
397                    or error_status == "UserCannotFindRequestedUser"
398                ):
399                    return NotFound(
400                        message=message,
401                        error_code=error_code,
402                        throttle_seconds=throttle_seconds,
403                        url=str(response.real_url),
404                        body=body,
405                        headers=response.headers,
406                        error_status=error_status,
407                        message_data=message_data,
408                    )
409
410                # Other 5xx errors.
411                else:
412                    return InternalServerError(
413                        message=message,
414                        error_code=error_code,
415                        throttle_seconds=throttle_seconds,
416                        url=str(response.real_url),
417                        body=body,
418                        headers=response.headers,
419                        error_status=error_status,
420                        message_data=message_data,
421                        http_status=status,
422                    )
423            # Something else.
424            else:
425                return HTTPException(
426                    message=message,
427                    error_code=error_code,
428                    throttle_seconds=throttle_seconds,
429                    url=str(response.real_url),
430                    body=body,
431                    headers=response.headers,
432                    error_status=error_status,
433                    message_data=message_data,
434                    http_status=status,
435                )

Immediately raise an exception based on the response.

def stringify_headers(headers: collections.abc.Mapping[str, typing.Any]) -> str:
438def stringify_headers(headers: collections.Mapping[str, typing.Any]) -> str:
439    return (
440        "{ \n"
441        + "\n".join(  # noqa: W503
442            f"{f'   {key}'}: {value}"
443            if key
444            not in {
445                "Authorization",
446                "X-API-KEY",
447                "client_secret",
448                "client_id",
449                "access_token",
450                "refresh_token",
451            }
452            else f"   {key}: REDACTED_TOKEN"
453            for key, value in headers.items()
454        )
455        + "\n}"  # noqa: W503
456    )